{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# python 笔记\n",
    "\n",
    "官方文档 https://docs.python.org/zh-cn/3.6/contents.html\n",
    "\n",
    "* [列表](#列表) \n",
    "* [随机数](#随机数)\n",
    "* [字符串内建函数](#字符串内建函数)\n",
    "* [format格式化函数](#format格式化函数)\n",
    "* [列表解析式](#列表解析式)\n",
    "* [Copy](#Copy)\n",
    "* [字典dict](#字典dict)\n",
    "* [集合set](#集合set)\n",
    "* [JSON](#JSON)\n",
    "* [文件输入输出](#文件输入输出)\n",
    "* [pickle](#pickle)\n",
    "* [文件操作](#文件操作)\n",
    "* [错误与异常](#错误与异常)\n",
    "* [函数](#函数)\n",
    "* [生成器](#生成器)\n",
    "* [装饰器](#装饰器)\n",
    "* [类](#类)\n",
    "* [正则表达式](#正则表达式)\n",
    "* [多线程编程](#多线程编程)\n",
    "* [定时器](#定时器)\n",
    "* [Enum](#Enum)\n",
    "* [namedtuple](#namedtuple)\n",
    "* [Counter](#Counter)\n",
    "* [defaultdict](#defaultdict)\n",
    "* [扑克牌](#扑克牌)\n",
    "* [网格化参数](#网格化参数)\n",
    "* [进程监控](#进程监控)\n",
    "* [tqdm](#tqdm)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Platform : linux [win32/linux]\n",
      "Systerm  : 3.6.8 (default, Jan 14 2019, 11:02:34) \n",
      "[GCC 8.0.1 20180414 (experimental) [trunk revision 259383]] \n",
      "Command  : ['/usr/local/lib/python3.6/dist-packages/ipykernel_launcher.py', '-f', '/root/.local/share/jupyter/runtime/kernel-bf50321c-139e-4dbd-ae30-73cf80b3bbee.json'] \n",
      "当前时间：20200101163138\n",
      "父进程ID  : 1134\n",
      "进程用户ID: 0\n",
      "进程群组ID: 0\n",
      "当前环境变量: environ({'PATH': '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', 'HOSTNAME': '281cff103ba9', 'TERM': 'xterm-color', 'LANG': 'C.UTF-8', 'HOME': '/root', 'JPY_PARENT_PID': '1', 'CLICOLOR': '1', 'PAGER': 'cat', 'GIT_PAGER': 'cat', 'MPLBACKEND': 'module://ipykernel.pylab.backend_inline'})\n"
     ]
    }
   ],
   "source": [
    "import time \n",
    "import os \n",
    "import sys\n",
    "\n",
    "print('Platform : {} [win32/linux]'.format(sys.platform))  # 当前平台信息 \n",
    "print('Systerm  : {} '.format(sys.version))\n",
    "print('Command  : {} '.format(sys.argv))  # 命令行传入参数\n",
    "print('当前时间：{}'.format(time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))))\n",
    "print('父进程ID  : {}'.format(os.getpid()))\n",
    "print('进程用户ID: {}'.format(os.getuid()))\n",
    "print('进程群组ID: {}'.format(os.getgid()))\n",
    "print('当前环境变量: {}'.format(os.environ))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on built-in module sys:\n",
      "\n",
      "NAME\n",
      "    sys\n",
      "\n",
      "MODULE REFERENCE\n",
      "    https://docs.python.org/3.6/library/sys\n",
      "    \n",
      "    The following documentation is automatically generated from the Python\n",
      "    source files.  It may be incomplete, incorrect or include features that\n",
      "    are considered implementation detail and may vary between Python\n",
      "    implementations.  When in doubt, consult the module reference at the\n",
      "    location listed above.\n",
      "\n",
      "DESCRIPTION\n",
      "    This module provides access to some objects used or maintained by the\n",
      "    interpreter and to functions that interact strongly with the interpreter.\n",
      "    \n",
      "    Dynamic objects:\n",
      "    \n",
      "    argv -- command line arguments; argv[0] is the script pathname if known\n",
      "    path -- module search path; path[0] is the script directory, else ''\n",
      "    modules -- dictionary of loaded modules\n",
      "    \n",
      "    displayhook -- called to show results in an interactive session\n",
      "    excepthook -- called to handle any uncaught exception other than SystemExit\n",
      "      To customize printing in an interactive session or to install a custom\n",
      "      top-level exception handler, assign other functions to replace these.\n",
      "    \n",
      "    stdin -- standard input file object; used by input()\n",
      "    stdout -- standard output file object; used by print()\n",
      "    stderr -- standard error object; used for error messages\n",
      "      By assigning other file objects (or objects that behave like files)\n",
      "      to these, it is possible to redirect all of the interpreter's I/O.\n",
      "    \n",
      "    last_type -- type of last uncaught exception\n",
      "    last_value -- value of last uncaught exception\n",
      "    last_traceback -- traceback of last uncaught exception\n",
      "      These three are only available in an interactive session after a\n",
      "      traceback has been printed.\n",
      "    \n",
      "    Static objects:\n",
      "    \n",
      "    builtin_module_names -- tuple of module names built into this interpreter\n",
      "    copyright -- copyright notice pertaining to this interpreter\n",
      "    exec_prefix -- prefix used to find the machine-specific Python library\n",
      "    executable -- absolute path of the executable binary of the Python interpreter\n",
      "    float_info -- a struct sequence with information about the float implementation.\n",
      "    float_repr_style -- string indicating the style of repr() output for floats\n",
      "    hash_info -- a struct sequence with information about the hash algorithm.\n",
      "    hexversion -- version information encoded as a single integer\n",
      "    implementation -- Python implementation information.\n",
      "    int_info -- a struct sequence with information about the int implementation.\n",
      "    maxsize -- the largest supported length of containers.\n",
      "    maxunicode -- the value of the largest Unicode code point\n",
      "    platform -- platform identifier\n",
      "    prefix -- prefix used to find the Python library\n",
      "    thread_info -- a struct sequence with information about the thread implementation.\n",
      "    version -- the version of this interpreter as a string\n",
      "    version_info -- version information as a named tuple\n",
      "    __stdin__ -- the original stdin; don't touch!\n",
      "    __stdout__ -- the original stdout; don't touch!\n",
      "    __stderr__ -- the original stderr; don't touch!\n",
      "    __displayhook__ -- the original displayhook; don't touch!\n",
      "    __excepthook__ -- the original excepthook; don't touch!\n",
      "    \n",
      "    Functions:\n",
      "    \n",
      "    displayhook() -- print an object to the screen, and save it in builtins._\n",
      "    excepthook() -- print an exception and its traceback to sys.stderr\n",
      "    exc_info() -- return thread-safe information about the current exception\n",
      "    exit() -- exit the interpreter by raising SystemExit\n",
      "    getdlopenflags() -- returns flags to be used for dlopen() calls\n",
      "    getprofile() -- get the global profiling function\n",
      "    getrefcount() -- return the reference count for an object (plus one :-)\n",
      "    getrecursionlimit() -- return the max recursion depth for the interpreter\n",
      "    getsizeof() -- return the size of an object in bytes\n",
      "    gettrace() -- get the global debug tracing function\n",
      "    setcheckinterval() -- control how often the interpreter checks for events\n",
      "    setdlopenflags() -- set the flags to be used for dlopen() calls\n",
      "    setprofile() -- set the global profiling function\n",
      "    setrecursionlimit() -- set the max recursion depth for the interpreter\n",
      "    settrace() -- set the global debug tracing function\n",
      "\n",
      "FUNCTIONS\n",
      "    __displayhook__ = displayhook(...)\n",
      "        displayhook(object) -> None\n",
      "        \n",
      "        Print an object to sys.stdout and also save it in builtins._\n",
      "    \n",
      "    __excepthook__ = excepthook(...)\n",
      "        excepthook(exctype, value, traceback) -> None\n",
      "        \n",
      "        Handle an exception by displaying it with a traceback on sys.stderr.\n",
      "    \n",
      "    call_tracing(...)\n",
      "        call_tracing(func, args) -> object\n",
      "        \n",
      "        Call func(*args), while tracing is enabled.  The tracing state is\n",
      "        saved, and restored afterwards.  This is intended to be called from\n",
      "        a debugger from a checkpoint, to recursively debug some other code.\n",
      "    \n",
      "    callstats(...)\n",
      "        callstats() -> tuple of integers\n",
      "        \n",
      "        Return a tuple of function call statistics, if CALL_PROFILE was defined\n",
      "        when Python was built.  Otherwise, return None.\n",
      "        \n",
      "        When enabled, this function returns detailed, implementation-specific\n",
      "        details about the number of function calls executed. The return value is\n",
      "        a 11-tuple where the entries in the tuple are counts of:\n",
      "        0. all function calls\n",
      "        1. calls to PyFunction_Type objects\n",
      "        2. PyFunction calls that do not create an argument tuple\n",
      "        3. PyFunction calls that do not create an argument tuple\n",
      "           and bypass PyEval_EvalCodeEx()\n",
      "        4. PyMethod calls\n",
      "        5. PyMethod calls on bound methods\n",
      "        6. PyType calls\n",
      "        7. PyCFunction calls\n",
      "        8. generator calls\n",
      "        9. All other calls\n",
      "        10. Number of stack pops performed by call_function()\n",
      "    \n",
      "    exc_info(...)\n",
      "        exc_info() -> (type, value, traceback)\n",
      "        \n",
      "        Return information about the most recent exception caught by an except\n",
      "        clause in the current stack frame or in an older stack frame.\n",
      "    \n",
      "    exit(...)\n",
      "        exit([status])\n",
      "        \n",
      "        Exit the interpreter by raising SystemExit(status).\n",
      "        If the status is omitted or None, it defaults to zero (i.e., success).\n",
      "        If the status is an integer, it will be used as the system exit status.\n",
      "        If it is another kind of object, it will be printed and the system\n",
      "        exit status will be one (i.e., failure).\n",
      "    \n",
      "    get_asyncgen_hooks(...)\n",
      "        get_asyncgen_hooks()\n",
      "        \n",
      "        Return a namedtuple of installed asynchronous generators hooks (firstiter, finalizer).\n",
      "    \n",
      "    get_coroutine_wrapper(...)\n",
      "        get_coroutine_wrapper()\n",
      "        \n",
      "        Return the wrapper for coroutine objects set by sys.set_coroutine_wrapper.\n",
      "    \n",
      "    getallocatedblocks(...)\n",
      "        getallocatedblocks() -> integer\n",
      "        \n",
      "        Return the number of memory blocks currently allocated, regardless of their\n",
      "        size.\n",
      "    \n",
      "    getcheckinterval(...)\n",
      "        getcheckinterval() -> current check interval; see setcheckinterval().\n",
      "    \n",
      "    getdefaultencoding(...)\n",
      "        getdefaultencoding() -> string\n",
      "        \n",
      "        Return the current default string encoding used by the Unicode \n",
      "        implementation.\n",
      "    \n",
      "    getdlopenflags(...)\n",
      "        getdlopenflags() -> int\n",
      "        \n",
      "        Return the current value of the flags that are used for dlopen calls.\n",
      "        The flag constants are defined in the os module.\n",
      "    \n",
      "    getfilesystemencodeerrors(...)\n",
      "        getfilesystemencodeerrors() -> string\n",
      "        \n",
      "        Return the error mode used to convert Unicode filenames in\n",
      "        operating system filenames.\n",
      "    \n",
      "    getfilesystemencoding(...)\n",
      "        getfilesystemencoding() -> string\n",
      "        \n",
      "        Return the encoding used to convert Unicode filenames in\n",
      "        operating system filenames.\n",
      "    \n",
      "    getprofile(...)\n",
      "        getprofile()\n",
      "        \n",
      "        Return the profiling function set with sys.setprofile.\n",
      "        See the profiler chapter in the library manual.\n",
      "    \n",
      "    getrecursionlimit(...)\n",
      "        getrecursionlimit()\n",
      "        \n",
      "        Return the current value of the recursion limit, the maximum depth\n",
      "        of the Python interpreter stack.  This limit prevents infinite\n",
      "        recursion from causing an overflow of the C stack and crashing Python.\n",
      "    \n",
      "    getrefcount(...)\n",
      "        getrefcount(object) -> integer\n",
      "        \n",
      "        Return the reference count of object.  The count returned is generally\n",
      "        one higher than you might expect, because it includes the (temporary)\n",
      "        reference as an argument to getrefcount().\n",
      "    \n",
      "    getsizeof(...)\n",
      "        getsizeof(object, default) -> int\n",
      "        \n",
      "        Return the size of object in bytes.\n",
      "    \n",
      "    getswitchinterval(...)\n",
      "        getswitchinterval() -> current thread switch interval; see setswitchinterval().\n",
      "    \n",
      "    gettrace(...)\n",
      "        gettrace()\n",
      "        \n",
      "        Return the global debug tracing function set with sys.settrace.\n",
      "        See the debugger chapter in the library manual.\n",
      "    \n",
      "    intern(...)\n",
      "        intern(string) -> string\n",
      "        \n",
      "        ``Intern'' the given string.  This enters the string in the (global)\n",
      "        table of interned strings whose purpose is to speed up dictionary lookups.\n",
      "        Return the string itself or the previously interned string object with the\n",
      "        same value.\n",
      "    \n",
      "    is_finalizing(...)\n",
      "        is_finalizing()\n",
      "        Return True if Python is exiting.\n",
      "    \n",
      "    set_asyncgen_hooks(...)\n",
      "        set_asyncgen_hooks(*, firstiter=None, finalizer=None)\n",
      "        \n",
      "        Set a finalizer for async generators objects.\n",
      "    \n",
      "    set_coroutine_wrapper(...)\n",
      "        set_coroutine_wrapper(wrapper)\n",
      "        \n",
      "        Set a wrapper for coroutine objects.\n",
      "    \n",
      "    setcheckinterval(...)\n",
      "        setcheckinterval(n)\n",
      "        \n",
      "        Tell the Python interpreter to check for asynchronous events every\n",
      "        n instructions.  This also affects how often thread switches occur.\n",
      "    \n",
      "    setdlopenflags(...)\n",
      "        setdlopenflags(n) -> None\n",
      "        \n",
      "        Set the flags used by the interpreter for dlopen calls, such as when the\n",
      "        interpreter loads extension modules.  Among other things, this will enable\n",
      "        a lazy resolving of symbols when importing a module, if called as\n",
      "        sys.setdlopenflags(0).  To share symbols across extension modules, call as\n",
      "        sys.setdlopenflags(os.RTLD_GLOBAL).  Symbolic names for the flag modules\n",
      "        can be found in the os module (RTLD_xxx constants, e.g. os.RTLD_LAZY).\n",
      "    \n",
      "    setprofile(...)\n",
      "        setprofile(function)\n",
      "        \n",
      "        Set the profiling function.  It will be called on each function call\n",
      "        and return.  See the profiler chapter in the library manual.\n",
      "    \n",
      "    setrecursionlimit(...)\n",
      "        setrecursionlimit(n)\n",
      "        \n",
      "        Set the maximum depth of the Python interpreter stack to n.  This\n",
      "        limit prevents infinite recursion from causing an overflow of the C\n",
      "        stack and crashing Python.  The highest possible limit is platform-\n",
      "        dependent.\n",
      "    \n",
      "    setswitchinterval(...)\n",
      "        setswitchinterval(n)\n",
      "        \n",
      "        Set the ideal thread switching delay inside the Python interpreter\n",
      "        The actual frequency of switching threads can be lower if the\n",
      "        interpreter executes long sequences of uninterruptible code\n",
      "        (this is implementation-specific and workload-dependent).\n",
      "        \n",
      "        The parameter must represent the desired switching delay in seconds\n",
      "        A typical value is 0.005 (5 milliseconds).\n",
      "    \n",
      "    settrace(...)\n",
      "        settrace(function)\n",
      "        \n",
      "        Set the global debug tracing function.  It will be called on each\n",
      "        function call.  See the debugger chapter in the library manual.\n",
      "\n",
      "DATA\n",
      "    __stderr__ = <_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF...\n",
      "    __stdin__ = <_io.TextIOWrapper name='<stdin>' mode='r' encoding='UTF-8...\n",
      "    __stdout__ = <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF...\n",
      "    abiflags = 'm'\n",
      "    api_version = 1013\n",
      "    argv = ['/usr/local/lib/python3.6/dist-packages/ipykernel_launcher.py'...\n",
      "    base_exec_prefix = '/usr'\n",
      "    base_prefix = '/usr'\n",
      "    builtin_module_names = ('_ast', '_bisect', '_blake2', '_codecs', '_col...\n",
      "    byteorder = 'little'\n",
      "    copyright = 'Copyright (c) 2001-2018 Python Software Foundati...ematis...\n",
      "    displayhook = <ipykernel.displayhook.ZMQShellDisplayHook object>\n",
      "    dont_write_bytecode = False\n",
      "    exec_prefix = '/usr'\n",
      "    executable = '/usr/bin/python3'\n",
      "    flags = sys.flags(debug=0, inspect=0, interactive=0, opt...ing=0, quie...\n",
      "    float_info = sys.float_info(max=1.7976931348623157e+308, max_...epsilo...\n",
      "    float_repr_style = 'short'\n",
      "    hash_info = sys.hash_info(width=64, modulus=2305843009213693...iphash2...\n",
      "    hexversion = 50727152\n",
      "    implementation = namespace(_multiarch='x86_64-linux-gnu', cache_t...in...\n",
      "    int_info = sys.int_info(bits_per_digit=30, sizeof_digit=4)\n",
      "    maxsize = 9223372036854775807\n",
      "    maxunicode = 1114111\n",
      "    meta_path = [<class '_frozen_importlib.BuiltinImporter'>, <class '_fro...\n",
      "    modules = {'IPython': <module 'IPython' from '/usr/local/lib/python3.6...\n",
      "    path = ['/usr/lib/python36.zip', '/usr/lib/python3.6', '/usr/lib/pytho...\n",
      "    path_hooks = [<class 'zipimport.zipimporter'>, <function FileFinder.pa...\n",
      "    path_importer_cache = {'/root/.ipython': FileFinder('/root/.ipython'),...\n",
      "    platform = 'linux'\n",
      "    prefix = '/usr'\n",
      "    ps1 = 'In : '\n",
      "    ps2 = '...: '\n",
      "    ps3 = 'Out: '\n",
      "    stderr = <ipykernel.iostream.OutStream object>\n",
      "    stdin = <_io.TextIOWrapper name='<stdin>' mode='r' encoding='UTF-8'>\n",
      "    stdout = <ipykernel.iostream.OutStream object>\n",
      "    thread_info = sys.thread_info(name='pthread', lock='semaphore', versio...\n",
      "    version = '3.6.8 (default, Jan 14 2019, 11:02:34) \\n[GCC 8.0.1 2018041...\n",
      "    version_info = sys.version_info(major=3, minor=6, micro=8, releaseleve...\n",
      "    warnoptions = []\n",
      "\n",
      "FILE\n",
      "    (built-in)\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help(sys)  # 以一种整齐美观的形式 显示对象的文档字符串， 如果没有提供任何参数， 则会进入交互式帮助 \n",
    "# dir(sys)  # 显示对象的属性，如果没有提供参数， 则显示全局变量的名字\n",
    "# type(obj)  # 返回对象的类型（返回值本身是一个 type 对象！）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdin",
     "output_type": "stream",
     "text": [
      "输入： input\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "输出： input\n"
     ]
    }
   ],
   "source": [
    "input_infor = input('输入：')\n",
    "print('输出： {}'.format(input_infor))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 列表"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'float'>\n",
      "True\n",
      "139670258831456\n",
      "24\n"
     ]
    }
   ],
   "source": [
    "a=100.0\n",
    "\n",
    "print(type(a))\n",
    "print(isinstance(a, float))\n",
    "print(id(a))\n",
    "print(sys.getsizeof(a))\n",
    "del a\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "【13/5 】 : 2.6\n",
      "【13//5】 : 2\n",
      "【13%5 】 : 3\n",
      "【商、余数】 : (2, 3)\n",
      "【指数】 : 32\n",
      "【round】 : 0.64\n"
     ]
    }
   ],
   "source": [
    "print('【13/5 】 :', 13/5)   # 真正除法\n",
    "print('【13//5】 :', 13//5)  # 商\n",
    "print('【13%5 】 :', 13%5)   # 余数\n",
    "print('【商、余数】 :', divmod(13, 5))   # 商、余数\n",
    "print('【指数】 :', 2**5)  # 指数\n",
    "print('【round】 :', round(0.636, 2))  # 得到最接近原数的整数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "【index(5)】： 4\n",
      "【min(a)】： 1\n",
      "【max(a)】： 7\n",
      "【len(a)】： 7\n",
      "【sum(a)】： 28\n",
      "【reversed(a)】： [7, 6, 5, 4, 3, 2, 1]\n",
      "【a[::-1]】： [7, 6, 5, 4, 3, 2, 1]\n",
      "【sorted(a)】： [7, 6, 5, 4, 3, 2, 1]\n",
      "【a[::2]】： [1, 3, 5, 7]\n"
     ]
    }
   ],
   "source": [
    "a = [1,2,3,4,5,6,7]\n",
    "print('【index(5)】：',a.index(5))\n",
    "print('【min(a)】：',min(a))\n",
    "print('【max(a)】：',max(a))\n",
    "print('【len(a)】：',len(a))\n",
    "print('【sum(a)】：',sum(a))\n",
    "print('【reversed(a)】：',list(reversed(a)))  # 逆序\n",
    "print('【a[::-1]】：',a[::-1]) # 逆序\n",
    "print('【sorted(a)】：',sorted(a, reverse=True))  # 排序\n",
    "print('【a[::2]】：',a[::2]) # "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[{'name': 'alice', 'score': 38}, {'name': 'christ', 'score': 28}, {'name': 'darl', 'score': 28}, {'name': 'bob', 'score': 18}]\n",
      "[['A3', 1], ['B1', 1], ['A3', 3], ['B1', 3]]\n",
      "[['A3', 3], ['A3', 1], ['B1', 3], ['B1', 1]]\n",
      "[['B1', 3], ['B1', 1], ['A3', 3], ['A3', 1]]\n",
      "[['A3', 1], ['A3', 3], ['B1', 1], ['B1', 3]]\n"
     ]
    }
   ],
   "source": [
    "# 多列排序 \n",
    "d1 = [{'name': 'alice', 'score': 38},\n",
    "      {'name': 'bob', 'score': 18},\n",
    "      {'name': 'darl', 'score': 28},\n",
    "      {'name': 'christ', 'score': 28}]\n",
    "print(sorted(d1, key=lambda x: (-x['score'], x['name'])))   \n",
    "\n",
    "\n",
    "d2 = [['A3', 1], ['A3', 3], ['B1', 1], ['B1', 3]]\n",
    "print(sorted(d2, key=lambda x: (x[1], x[0])))\n",
    "print(sorted(d2, key=lambda x: (x[0][0], -x[1])))\n",
    "print(sorted(d2, key=lambda x: (x[0][-1], -x[1]), reverse=False))\n",
    "print(sorted(d2, key=lambda x: (x[0][-1], -x[1]), reverse=True))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 随机数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "n--m范围内的一个随机数 random.randint(n,m)    :   [16, 16, 10, 14, 18, 17, 16, 14, 17, 15]\n",
      "产生0到1之间的浮点数:  random.random()        :   [0.5833820394550312, 0.9081128851953352, 0.5046868558173903, 0.28183784439970383, 0.7558042041572239]\n",
      "n--m之间的浮点数:  random.uniform(n,m)        :   [0.9618368996675332, 0.9250506341362441, 0.990974625596824, 0.9982785476037653, 0.981021723599659]\n",
      "n---m间隔为k的整数: random.randrange(n,m,k)   :   [13, 16, 10, 10, 16, 19, 10, 16, 19, 16]\n",
      "序列中随机选取一个元素:random.choice(\"abcdef\"):   ['e', 'f', 'b', 'e', 'd', 'd', 'e', 'c', 'a', 'e']\n",
      "序列进行打乱操作: random.shuffle([1,3,5,6,7]) :   [6, 3, 5, 7, 1]\n",
      "random.sampe 随机取样：  [6, 7, 3, 1]\n"
     ]
    }
   ],
   "source": [
    "import random\n",
    "\n",
    "# 设置随机种子\n",
    "random.seed(0)  # 默认为 None\n",
    "\n",
    "print('n--m范围内的一个随机数 random.randint(n,m)    :  ', [random.randint(10,20) for i in range(10)])\n",
    "print('产生0到1之间的浮点数:  random.random()        :  ', [random.random() for i in range(5)])\n",
    "print('n--m之间的浮点数:  random.uniform(n,m)        :  ', [random.uniform(0.9,1.0) for i in range(5)])\n",
    "print('n---m间隔为k的整数: random.randrange(n,m,k)   :  ', [random.randrange(10,20,3) for i in range(10)])\n",
    "print('序列中随机选取一个元素:random.choice(\"abcdef\"):  ', [random.choice(\"abcdef\") for i in range(10)])\n",
    "\n",
    "a_list = [1,3,5,6,7]\n",
    "random.shuffle(a_list)  # 直接在原列表中打乱顺序\n",
    "print('序列进行打乱操作: random.shuffle([1,3,5,6,7]) :  ', a_list)\n",
    "\n",
    "print('random.sampe 随机取样： ', random.sample(a_list, 4))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 字符串内建函数\n",
    "help(str)\n",
    "\n",
    "string.capitalize() 把字符串的第一个字符大写   \n",
    "string.center(width) 返回一个原字符串居中,并使用空格填充至长度 width 的新字符串   \n",
    "string.count(str, beg=0, end=len(string)) 返回 str 在 string 里面出现的次数，如果 beg 或者 end 指定则返回指定范围内 str 出现的次数    \n",
    "string.decode(encoding='UTF-8', errors='strict') 以 encoding 指定的编码格式解码 string，如果出错默认报一个 ValueError 的 异 常 ， 除 非 errors 指 定 的 是 'ignore' 或 者'replace'   \n",
    "string.encode(encoding='UTF-8', errors='strict') 以 encoding 指定的编码格式编码 string，如果出错默认报一个ValueError 的异常，除非 errors 指定的是'ignore'或者'replace'   \n",
    "string.endswith(obj, beg=0, end=len(string))b,e检查字符串是否以 obj 结束，如果 beg 或者 end 指定则检查指定的范围内是否以 obj 结束，如果是，返回 True,否则返回 False.   \n",
    "string.expandtabs(tabsize=8)把字符串 string 中的 tab 符号转为空格，格数 tabsize 是 8.   \n",
    "string.find(str, beg=0, end=len(string)) 检测 str 是否包含在 string 中，如果 beg 和 end 指定范围，则检查是否包含在指定范围内，如果是返回开始的索引值，否则返回-1   \n",
    "string.index(str, beg=0, end=len(string)) 跟 find()方法一样，只不过如果 str不在 string中会报一个异常.   \n",
    "string.isalnum()a, b, c R 如果 string 至少有一个字符并且所有字符都是字母或数字则返回 True,否则返回 False     \n",
    "string.isalpha()a, b, c 如果 string 至少有一个字符并且所有字符都是字母则返回 True,否则返回 False   \n",
    "string.isdecimal()b, c, d 如果 string 只包含十进制数字则返回 True 否则返回 False.   \n",
    "string.isdigit()b, c 如果 string 只包含数字则返回 True 否则返回 False.   \n",
    "string.islower()b, c 如果 string 中包含至少一个区分大小写的字符，并且所有这些(区分大小写的)字符都是小写，则返回 True，否则返回 False   \n",
    "string.isnumeric()b, c, d 如果 string 中只包含数字字符，则返回 True，否则返回 False   \n",
    "string.isspace()b, c 如果 string 中只包含空格，则返回 True，否则返回 False.   \n",
    "string.istitle()b, c 如果 string 是标题化的(见 title())则返回 True，否则返回 False   \n",
    "string.isupper()b, c 如果 string 中包含至少一个区分大小写的字符，并且所有这些(区分大小写的)字符都是大写，则返回 True，否则返回 False   \n",
    "string.join(seq) Merges (concatenates)以 string 作为分隔符，将 seq 中所有的元素(的字符串表示)合并为一个新的字符串   \n",
    "string.ljust(width)返回一个原字符串左对齐,并使用空格填充至长度 width 的新字符串   \n",
    "string.lower() 转换 string 中所有大写字符为小写.   \n",
    "string.lstrip() 截掉 string 左边的空格   \n",
    "string.partition(str)e 有点像 find()和 split()的结合体,从 str 出现的第一个位置起,把 字 符 串 string 分 成 一 个 3 元 素 的 元 组 (string_pre_str,str,string_post_str),如果 string 中不包含str 则 string_pre_str == string.   \n",
    "string.replace(str1, str2, num=string.count(str1))把 string 中的 str1 替换成 str2,如果 num 指定，则替换不超过 num 次.   \n",
    "string.rfind(str, beg=0,end=len(string))类似于 find()函数，不过是从右边开始查找.   \n",
    "string.rindex( str, beg=0,end=len(string)) 类似于 index()，不过是从右边开始.   \n",
    "string.rjust(width)返回一个原字符串右对齐,并使用空格填充至长度 width 的新字符串   \n",
    "string.rpartition(str)e 类似于 partition()函数,不过是从右边开始查找.   \n",
    "string.rstrip() 删除 string 字符串末尾的空格.   \n",
    "string.split(str=\"\", num=string.count(str)) 以 str 为分隔符切片 string，如果 num有指定值，则仅分隔 num 个子字符串   \n",
    "string.splitlines(num=string.count('\\n'))b, c按照行分隔，返回一个包含各行作为元素的列表，如果 num 指定则仅切片 num 个行.   \n",
    "string.startswith(obj, beg=0,end=len(string))b, e检查字符串是否是以 obj 开头，是则返回 True，否则返回 False。如果beg 和 end 指定值，则在指定范围内检查.   \n",
    "string.strip([obj]) 在 string 上执行 lstrip()和 rstrip()   \n",
    "string.swapcase() 翻转 string 中的大小写   \n",
    "string.title()b, c 返回\"标题化\"的 string,就是说所有单词都是以大写开始，其余字母均为小写(见 istitle())   \n",
    "string.translate(str, del=\"\") 根据 str 给出的表(包含 256 个字符)转换 string 的字符,要过滤掉的字符放到 del 参数中   \n",
    "string.upper() 转换 string 中的小写字母为大写   \n",
    "string.zfill(width) 返回长度为 width 的字符串，原字符串 string 右对齐，前面填充0  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "【hex(255)】： 0xff\n",
      "【oct(255)】： 0o377\n",
      "【ord(”a“)】： 97\n",
      "【chr(97) 】： a\n"
     ]
    }
   ],
   "source": [
    "print('【hex(255)】：', hex(255))  # 十六进制\n",
    "print('【oct(255)】：', oct(255))  # 八进制\n",
    "\n",
    "print('【ord(”a“)】：', ord('a'))  # ASCII 转换函数\n",
    "print('【chr(97) 】：', chr(97))   # ASCII 转换函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3242\n",
      "False\n",
      "True\n",
      "True\n",
      "True\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "a='adfa12'\n",
    "a=str(3242)\n",
    "print(a)\n",
    "print(a.isalpha())  # 所有字符都是字母\n",
    "print(a.isnumeric())  # 检测字符串是否只由数字组成\n",
    "print(a.isalnum())   # 检测字符串是否由字母和数字组成\n",
    "print(a.isdecimal())  # 字符串是否只包含十进制字符\n",
    "print(a.isdigit())  # 检测字符串是否只由数字组成\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "raw                   4   <class 'str'> :  香港演员\n",
      "s_encode_unicode     24   <class 'bytes'> :  b'\\\\u9999\\\\u6e2f\\\\u6f14\\\\u5458'\n",
      "s_encode_unicode_d    4   <class 'str'> :  香港演员\n",
      "s_encode_unicode_d2  24   <class 'str'> :  \\u9999\\u6e2f\\u6f14\\u5458\n",
      "s_encode_unicode_d3   4   <class 'str'> :  香港演员\n",
      "s_encode_utf8        12   <class 'bytes'> :  b'\\xe9\\xa6\\x99\\xe6\\xb8\\xaf\\xe6\\xbc\\x94\\xe5\\x91\\x98'\n",
      "s_encode_utf8_d       4   <class 'str'> :  香港演员\n",
      "s_encode_gbk          8   <class 'bytes'> :  b'\\xcf\\xe3\\xb8\\xdb\\xd1\\xdd\\xd4\\xb1'\n",
      "s_encode_gbk_d        4   <class 'str'> :  香港演员\n"
     ]
    }
   ],
   "source": [
    "s = '香港演员'\n",
    "s_encode_unicode = s.encode('unicode_escape')\n",
    "s_encode_unicode_d = s_encode_unicode.decode(\"unicode_escape\")\n",
    "s_encode_unicode_d2 = s_encode_unicode.decode('utf8')\n",
    "s_encode_unicode_d3 = s_encode_unicode_d2.encode('utf-8').decode(\"unicode_escape\")\n",
    "\n",
    "s_encode_utf8= s.encode('utf-8')\n",
    "s_encode_utf8_d= s_encode_utf8.decode('utf-8')\n",
    "\n",
    "s_encode_gbk= s.encode('gbk')\n",
    "s_encode_gbk_d= s_encode_gbk.decode('gbk')\n",
    "\n",
    "print('{:20s} {:2d}   {} :  {}'.format('raw', len(s), type(s), s))\n",
    "print('{:20s} {:2d}   {} :  {}'.format('s_encode_unicode', len(s_encode_unicode), type(s_encode_unicode), s_encode_unicode))\n",
    "print('{:20s} {:2d}   {} :  {}'.format('s_encode_unicode_d', len(s_encode_unicode_d), type(s_encode_unicode_d), s_encode_unicode_d))\n",
    "print('{:20s} {:2d}   {} :  {}'.format('s_encode_unicode_d2', len(s_encode_unicode_d2), type(s_encode_unicode_d2), s_encode_unicode_d2))\n",
    "print('{:20s} {:2d}   {} :  {}'.format('s_encode_unicode_d3', len(s_encode_unicode_d3), type(s_encode_unicode_d3), s_encode_unicode_d3))\n",
    "print('{:20s} {:2d}   {} :  {}'.format('s_encode_utf8', len(s_encode_utf8), type(s_encode_utf8), s_encode_utf8))\n",
    "print('{:20s} {:2d}   {} :  {}'.format('s_encode_utf8_d', len(s_encode_utf8_d), type(s_encode_utf8_d), s_encode_utf8_d))\n",
    "print('{:20s} {:2d}   {} :  {}'.format('s_encode_gbk', len(s_encode_gbk), type(s_encode_gbk), s_encode_gbk))\n",
    "print('{:20s} {:2d}   {} :  {}'.format('s_encode_gbk_d', len(s_encode_gbk_d), type(s_encode_gbk_d), s_encode_gbk_d))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## format格式化函数\n",
    "https://www.runoob.com/python/att-string-format.html?ivk_sa=1023231z"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\"{} {}\".format(\"hello\", \"world\")                   : hello world\n",
      "\"{} {}\".format(*(\"hello\", \"world\"))                : hello world\n",
      "\"{b} {a}\".format(**{\"a\":\"Hello\", \"b\":\"world\"})     : world Hello\n",
      "\"{1} {0} {1}\".format(\"hello\", \"world\")             : world hello world\n",
      "中间对齐 \"{:^10d}\".format(10)           : |    10    |\n",
      "左边对齐 \"{:<10d}\".format(10)           : |10        |\n",
      "右边对齐 \"{:>010d}\".format(10)          : |0000000010|\n",
      "逗号分隔 \"{:10,}\".format(1000000)       : | 1,000,000|\n",
      "带符号+  \"{:+10.3f}\".format(0.324)      : |    +0.324|\n",
      "带符号+  \"{:+10.3f}\".format(-0.324)     : |    -0.324|\n",
      "百分比%  \"{:10.1%}\".format(0.324)       : |     32.4%|\n"
     ]
    }
   ],
   "source": [
    "str_a = '\"{} {}\".format(\"hello\", \"world\")'        # 未设置指定位置\n",
    "print('{:50s} : {}'.format(str_a, eval(str_a)))\n",
    "str_a = '\"{} {}\".format(*(\"hello\", \"world\"))'    # 未设置指定位置\n",
    "print('{:50s} : {}'.format(str_a, eval(str_a)))\n",
    "str_a = '\"{b} {a}\".format(**{\"a\":\"Hello\", \"b\":\"world\"})'  # 设置指定位置\n",
    "print('{:50s} : {}'.format(str_a, eval(str_a)))\n",
    "str_a = '\"{1} {0} {1}\".format(\"hello\", \"world\")' # 设置指定位置\n",
    "print('{:50s} : {}'.format(str_a, eval(str_a)))\n",
    "\n",
    "str_a = '\"{:^10d}\".format(10)'  # 中间对齐\n",
    "print('{} {:30s} : |{}|'.format('中间对齐', str_a, eval(str_a)))\n",
    "str_a = '\"{:<10d}\".format(10)'  # 左边对齐\n",
    "print('{} {:30s} : |{}|'.format('左边对齐', str_a, eval(str_a)))\n",
    "str_a = '\"{:>010d}\".format(10)'  # 右边对齐 补零\n",
    "print('{} {:30s} : |{}|'.format('右边对齐', str_a, eval(str_a)))\n",
    "\n",
    "str_a = '\"{:10,}\".format(1000000)'  # 逗号分隔\n",
    "print('{} {:30s} : |{}|'.format('逗号分隔', str_a, eval(str_a)))\n",
    "\n",
    "str_a = '\"{:+10.3f}\".format(0.324)'  # 带符号+\n",
    "print('{} {:30s} : |{}|'.format('带符号+ ', str_a, eval(str_a)))\n",
    "str_a = '\"{:+10.3f}\".format(-0.324)'  # 带符号+\n",
    "print('{} {:30s} : |{}|'.format('带符号+ ', str_a, eval(str_a)))\n",
    "str_a = '\"{:10.1%}\".format(0.324)'  # 百分比%\n",
    "print('{} {:30s} : |{}|'.format('百分比% ', str_a, eval(str_a)))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 列表解析式"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['1: adf', '2: qaef']\n",
      "{'2: qaef', '1: adf'}\n",
      "[['0-1', '0-3', '0-4'], ['1-a', '1-d', '1-f'], ['2-q', '2-a', '2-e', '2-f']]\n",
      "['00-1', '01-3', '02-4', '10-a', '11-d', '12-f', '20-q', '21-a', '22-e', '23-f']\n",
      "['1-1', '1-2', '1-3', '1-4', '1-5', '1-6', '1-7', '1-8', '1-9', '2-2', '2-3', '2-4', '2-5', '2-6', '2-7', '2-8', '2-9', '3-3', '3-4', '3-5', '3-6', '3-7', '3-8', '3-9', '4-4', '4-5', '4-6', '4-7', '4-8', '4-9', '5-5', '5-6', '5-7', '5-8', '5-9', '6-6', '6-7', '6-8', '6-9', '7-7', '7-8', '7-9', '8-8', '8-9', '9-9']\n"
     ]
    }
   ],
   "source": [
    "a = ['134', 'adf', 'qaef']\n",
    "\n",
    "# 单层嵌套 列表\n",
    "print(['{}: {}'.format(i, x) for i, x in enumerate(a) if i != 0])\n",
    "# 单层嵌套 字典\n",
    "print({'{}: {}'.format(i, x) for i, x in enumerate(a) if i != 0})\n",
    "\n",
    "# 多层嵌套\n",
    "print([['{}-{}'.format(i, x_i) for x_i in x] for i, x in enumerate(a)])\n",
    "# 多层嵌套\n",
    "print(['{}{}-{}'.format(i, j, x_i) for i, x in enumerate(a) for j, x_i in enumerate(x) ])\n",
    "# 多层嵌套\n",
    "print(['{}-{}'.format(x, y)  for x in range(1,10)  for y in range(1,10) if x <= y])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## Copy\n",
    "`copy.copy()` 进行浅拷贝操作   \n",
    "`copy.deepcopy()` 进行深拷贝操作  \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "直接赋值           【a】 id:139670258591176  value:[1, ['x', 'y', [1, 2, 3]]]  \n",
      "【a】 id:139670258591176  value:['浅层', ['深层', 'y', ['深深层', 2, 3]]]  \n",
      "【b】 id:139670258591176  value:['浅层', ['深层', 'y', ['深深层', 2, 3]]]  \n",
      "\n",
      "copy.copy          【a】 id:139670258698696  value:[1, ['x', 'y', [1, 2, 3]]]  \n",
      "【a】 id:139670258698696  value:[1, ['深层', 'y', ['深深层', 2, 3]]]  \n",
      "【b】 id:139670258698888  value:['浅层', ['深层', 'y', ['深深层', 2, 3]]]  \n",
      "\n",
      "copy.deepcopy      【a】 id:139670258589960  value:[1, ['x', 'y', [1, 2, 3]]]  \n",
      "【a】 id:139670258589960  value:[1, ['x', 'y', [1, 2, 3]]]  \n",
      "【b】 id:139670258698696  value:['浅层', ['深层', 'y', ['深深层', 2, 3]]]  \n",
      "\n"
     ]
    }
   ],
   "source": [
    "import copy\n",
    "a = [1, ['x', 'y', [1,2,3]]]\n",
    "print('直接赋值           【a】 id:{}  value:{}  '.format(id(a), a))\n",
    "b = a\n",
    "b[0] = '浅层'\n",
    "b[1][0] = '深层'\n",
    "b[1][2][0] = '深深层'\n",
    "print('【a】 id:{}  value:{}  \\n【b】 id:{}  value:{}  \\n'.format(id(a), a, id(b), b))\n",
    "\n",
    "a = [1, ['x', 'y', [1,2,3]]]\n",
    "print('copy.copy          【a】 id:{}  value:{}  '.format(id(a), a))\n",
    "b = copy.copy(a)\n",
    "b[0] = '浅层'\n",
    "b[1][0] = '深层'\n",
    "b[1][2][0] = '深深层'\n",
    "print('【a】 id:{}  value:{}  \\n【b】 id:{}  value:{}  \\n'.format(id(a), a, id(b), b))\n",
    "\n",
    "a = [1, ['x', 'y', [1,2,3]]]\n",
    "print('copy.deepcopy      【a】 id:{}  value:{}  '.format(id(a), a))\n",
    "b = copy.deepcopy(a)\n",
    "b[0] = '浅层'\n",
    "b[1][0] = '深层'\n",
    "b[1][2][0] = '深深层'\n",
    "print('【a】 id:{}  value:{}  \\n【b】 id:{}  value:{}  \\n'.format(id(a), a, id(b), b))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 字典dict"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "更新字典:   {'host': 'NewEarth', 'port': 80, 'server': 'http'}\n",
      "字典 Keys:   dict_keys(['host', 'port', 'server'])\n",
      "字典 values:   dict_values(['NewEarth', 80, 'http'])\n",
      "字典 items:   dict_items([('host', 'NewEarth'), ('port', 80), ('server', 'http')])\n",
      "返回Key、Values:   port 80\n",
      "无Key返回默认值:   DefaultValue\n",
      "返回并删除Key:   NewEarth\n",
      "更新字典:   {'port': 80, 'server': 'http'}\n",
      "Key Value 互换： {1: 'a', 3: 'b', 2: 'c'}\n",
      "Key  值排序：  ['a', 'b', 'c']\n",
      "Value值排序：  [('a', 1), ('c', 2), ('b', 3)]\n"
     ]
    }
   ],
   "source": [
    "dict1= {'host':'Earth', 'port':80}\n",
    "dict2= {'host':'NewEarth', 'server':'http'}\n",
    "\n",
    "# 更新字典\n",
    "dict1.update(dict2)\n",
    "print('更新字典:  ', dict1)\n",
    "print('字典 Keys:  ', dict1.keys())\n",
    "print('字典 values:  ', dict1.values())\n",
    "print('字典 items:  ', dict1.items())\n",
    "print('返回Key、Values:  ', 'port', dict1['port'])\n",
    "print('无Key返回默认值:  ', dict1.get('key', 'DefaultValue'))\n",
    "print('返回并删除Key:  ', dict1.pop('host', 'DefaultValue'))\n",
    "print('更新字典:  ', dict1)\n",
    "\n",
    "# 字典排序\n",
    "dict_a = {'a': 1, 'b': 3,  'c': 2}\n",
    "print('Key Value 互换：', {value:key for key, value in dict_a.items()})\n",
    "print('Key  值排序： ', sorted(dict_a))\n",
    "print('Value值排序： ', sorted(dict_a.items(), key=lambda x: x[1]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 集合set"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a:                  : {'3', '1', '2'}\n",
      "a.add(\"z\")          : {'3', '1', 'z', '2'}\n",
      "a.update(\"pypi\")    : {'p', 'y', '3', 'i', '1', 'z', '2'}\n",
      "a.remove(\"z\")       : {'p', 'y', '3', 'i', '1', '2'}\n",
      "\n",
      "Raw a               : {'*', '#', '3', '1', '2'}\n",
      "Raw b               : {'c', 'a', '*', '#', 'b'}\n",
      "并集 a|b              : {'c', 'a', '*', '#', '3', '1', 'b', '2'}\n",
      "交集 a&b              : {'#', '*'}\n",
      "差集 a-b              : {'3', '1', '2'}\n",
      "差集 b-a              : {'c', 'a', 'b'}\n",
      "异或 a^b              : {'c', 'a', '1', '3', 'b', '2'}\n",
      "异或 b^a              : {'c', 'a', 'b', '3', '1', '2'}\n",
      "子集 set('123') < set('1234')   : True\n",
      "子集 set('123a') < set('1234')  : False\n",
      "子集 set('1234') <= set('1234') : True\n"
     ]
    }
   ],
   "source": [
    "a = set(['1', '2', '3'])\n",
    "print('{:20s}: {}'.format('a: ', a))\n",
    "\n",
    "# 新增\n",
    "a.add('z')\n",
    "print('{:20s}: {}'.format('a.add(\"z\")', a))\n",
    "# 更新    \n",
    "a.update('pypi')\n",
    "print('{:20s}: {}'.format('a.update(\"pypi\")', a))\n",
    "# 删除\n",
    "a.remove('z')\n",
    "print('{:20s}: {}\\n'.format('a.remove(\"z\")', a))\n",
    "\n",
    "a = set('123*#')\n",
    "b = set('abc*#')\n",
    "print('{:20s}: {}'.format('Raw a', a))\n",
    "print('{:20s}: {}'.format('Raw b', b))\n",
    "# 并集 |\n",
    "print('{:20s}: {}'.format('并集 a|b', a|b))\n",
    "# 交集\n",
    "print('{:20s}: {}'.format('交集 a&b', a&b))\n",
    "# 差集\n",
    "print('{:20s}: {}'.format('差集 a-b', a-b))\n",
    "print('{:20s}: {}'.format('差集 b-a', b-a))\n",
    "# 异或\n",
    "print('{:20s}: {}'.format('异或 a^b', a^b))\n",
    "print('{:20s}: {}'.format('异或 b^a', b^a))\n",
    "\n",
    "# 子集\n",
    "print('{:30s}: {}'.format(\"子集 set('123') < set('1234')\", set('123') < set('1234')))\n",
    "print('{:30s}: {}'.format(\"子集 set('123a') < set('1234')\", set('123a') < set('1234')))\n",
    "print('{:30s}: {}'.format(\"子集 set('1234') <= set('1234')\", set('1234') <= set('1234')))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## JSON\n",
    "\n",
    "ensure_ascii  `False` 显示中文  `True`  显示编码  \n",
    "sort_keys     `False` 不排序    `True`  排序  \n",
    "indent         tab 空格数量  \n",
    "cls            序列化类函数  \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "JSON   2.0.9\n"
     ]
    }
   ],
   "source": [
    "import json\n",
    "import numpy as np \n",
    "print('JSON   {}'.format(json.__version__))\n",
    "\n",
    "# ######### 序列化函数\n",
    "class JsonEncoder(json.JSONEncoder):\n",
    "    \"\"\" Special json encoder for numpy types \"\"\"    \n",
    "    def default(self, obj):\n",
    "        if isinstance(obj, np.integer):\n",
    "            return int(obj)\n",
    "        elif isinstance(obj, np.floating):\n",
    "            return float(obj)\n",
    "        elif isinstance(obj, np.ndarray):\n",
    "            return obj.tolist()\n",
    "        elif isinstance(obj, datetime):                                 \n",
    "            return obj.__str__()\n",
    "        else:\n",
    "            return super(JsonEncoder, self).default(obj)\n",
    "\n",
    "# demo 数据        \n",
    "response = {'String': ['Helllo Json', 0.3],\n",
    "            'Chinese': '你好',\n",
    "            'time': time.time(),\n",
    "            'np_array': np.array([3, -10])}        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "字典转化成 JSON 字符串 :\n",
      " {\n",
      "    \"Chinese\": \"你好\",\n",
      "    \"String\": [\n",
      "        \"Helllo Json\",\n",
      "        0.3\n",
      "    ],\n",
      "    \"np_array\": [\n",
      "        3,\n",
      "        -10\n",
      "    ],\n",
      "    \"time\": 1577896328.9842625\n",
      "}\n",
      "\n",
      "字符串转换成 JSON 字典 :\n",
      "{'Chinese': '你好', 'String': ['Helllo Json', 0.3], 'np_array': [3, -10], 'time': 1577896328.9842625}\n",
      "['Helllo Json', 0.3]\n",
      "\n",
      "读取 JSON 文件 :\n",
      "{'Chinese': '你好', 'String': ['Helllo Json', 0.3], 'np_array': [3, -10], 'time': 1577896328.9842625}\n"
     ]
    }
   ],
   "source": [
    "# ################################################################# 字典转化成 JSON 字符串 \n",
    "## TypeError: Object of type 'ndarray' is not JSON serializable\n",
    "# print(json.dumps(response, ensure_ascii=False, sort_keys=True, indent=4))   \n",
    "\n",
    "response_0 = json.dumps(response, ensure_ascii=False, sort_keys=True, indent=4, cls=JsonEncoder)\n",
    "print('字典转化成 JSON 字符串 :\\n', response_0)\n",
    "\n",
    "# ################################################################# 字符串转换成 JSON 字典\n",
    "json_dict = json.loads(response_0)\n",
    "print('\\n字符串转换成 JSON 字典 :')\n",
    "print(json_dict)\n",
    "print(json_dict['String'])\n",
    "\n",
    "# ################################################################# 保存 JSON 文件\n",
    "os.makedirs('./_temp', exist_ok=True)\n",
    "with open('./_temp/json_demo.json', 'w', encoding='utf-8') as f_json:\n",
    "    json.dump(json_dict, f_json, indent=4, ensure_ascii=False, sort_keys=True)   \n",
    "\n",
    "# ################################################################# 读取 JSON 文件\n",
    "with open('./_temp/json_demo.json', 'r', encoding='utf-8') as f_json:\n",
    "    json_dict_2 = json.load(f_json)   \n",
    "print('\\n读取 JSON 文件 :')    \n",
    "print(json_dict_2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 文件输入输出"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "                      20\n",
      "Txt Test\\n            29\n",
      "asdf\\n                34\n",
      "Start\\n               6\n",
      "\n",
      "open(file_path, 'r', encoding='utf-8')\n",
      "Start\n",
      "Txt Test\n",
      "asdf\n",
      "\n",
      "open(file_path, 'rb')\n",
      "b'Start\\n'\n",
      "Byte->Unicode:   Start\n",
      "b'              Txt Test\\n'\n",
      "Byte->Unicode:   Txt Test\n",
      "b'asdf\\n'\n",
      "Byte->Unicode:   asdf\n"
     ]
    }
   ],
   "source": [
    "os.makedirs('./_temp', exist_ok=True)\n",
    "file_path = r'./_temp/test.txt'\n",
    "\n",
    "# 文件写入\n",
    "with open(file_path, 'w', encoding='utf-8') as f:\n",
    "    f.write(' '*20)    \n",
    "    print('{:20s}  {}'.format('',f.tell()))\n",
    "    f.write('Txt Test\\n')\n",
    "    print('{:20s}  {}'.format('Txt Test\\\\n', f.tell()))\n",
    "    f.write('asdf\\n')\n",
    "    print('{:20s}  {}'.format('asdf\\\\n', f.tell()))\n",
    "    f.seek(0, 0) # 指针返回文件开始  seek(off, whence=0, /) 从whence(0代表文件开始，1代表当前位置，2代表文件结尾) 偏移 off 字节\n",
    "    f.write('Start\\n')\n",
    "    print('{:20s}  {}'.format('Start\\\\n', f.tell()))\n",
    "    \n",
    "# 文件读取 r   \n",
    "print(\"\\nopen(file_path, 'r', encoding='utf-8')\")\n",
    "for line_i in  open(file_path, 'r', encoding='utf-8'):\n",
    "    print(line_i.strip())\n",
    "    \n",
    "# 文件读取 rb    \n",
    "print(\"\\nopen(file_path, 'rb')\")    \n",
    "for line_i in  open(file_path, 'rb'):\n",
    "    print(line_i)\n",
    "    print('Byte->Unicode:  ', line_i.decode().strip())  # byte 转换成 unicode\n",
    " "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## pickle"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "初始值   ： ['123', ('Hello', 1, 3, 4), {'Key': 'Values'}]\n",
      "pickle 后： b'\\x80\\x03]q\\x00(X\\x03\\x00\\x00\\x00123q\\x01(X\\x05\\x00\\x00\\x00Helloq\\x02K\\x01K\\x03K\\x04tq\\x03}q\\x04X\\x03\\x00\\x00\\x00Keyq\\x05X\\x06\\x00\\x00\\x00Valuesq\\x06se.'\n",
      "loads 后 比对： True\n",
      "loads 后 比对： True\n"
     ]
    }
   ],
   "source": [
    "import pickle\n",
    "a=['123', ('Hello', 1,3,4),{'Key':'Values'}]\n",
    "a_pickle = pickle.dumps(a)\n",
    "\n",
    "print('初始值   ：', a)\n",
    "print('pickle 后：',a_pickle)\n",
    "print('loads 后 比对：',pickle.loads(a_pickle) == a)\n",
    "\n",
    "file_path = r'./_temp/test.pickle'\n",
    "# 文件写入\n",
    "with open(file_path, 'wb') as f:\n",
    "    pickle.dump(a, file=f)\n",
    "# 文件读取\n",
    "with open(file_path, 'rb') as f:\n",
    "    a_load = pickle.load(f)\n",
    "print('loads 后 比对：',a_load == a)    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 文件操作"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "当前路径                          : /tf/PythonStudyNotes\n",
      "FilePath                          : /tf/PythonStudyNotes/_temp/test.txt\n",
      "文件名称                          : test.txt\n",
      "路径名称                          : /tf/PythonStudyNotes/_temp\n",
      "各级路径                          : ['', 'tf', 'PythonStudyNotes', '_temp', 'test.txt']\n",
      "文件是否存在                      : True\n",
      "是否文件                          : True\n",
      "是否文件夹                        : False\n",
      "getsize(byte) 文件大小            : 34\n",
      "getctime 创建时间                 : 1577896331.715123\n",
      "getmtime 修改时间                 : 1577896331.715123\n"
     ]
    }
   ],
   "source": [
    "file_path = r'./_temp/test.txt'\n",
    "print('{:30s}: {}'.format('当前路径', os.path.abspath(os.getcwd())))\n",
    "print('{:34s}: {}'.format('FilePath', os.path.abspath(file_path)))\n",
    "print('{:30s}: {}'.format('文件名称', os.path.basename(file_path)))\n",
    "print('{:30s}: {}'.format('路径名称', os.path.abspath(os.path.dirname(file_path))))\n",
    "print('{:30s}: {}'.format('各级路径', os.path.abspath(file_path).split(os.path.sep)))\n",
    "print('{:28s}: {}'.format('文件是否存在', os.path.exists(file_path)))\n",
    "print('{:30s}: {}'.format('是否文件', os.path.isfile(file_path)))\n",
    "print('{:29s}: {}'.format('是否文件夹', os.path.isdir(file_path)))\n",
    "print('{:30s}: {}'.format('getsize(byte) 文件大小', os.path.getsize(file_path)))\n",
    "print('{:30s}: {}'.format('getctime 创建时间', os.path.getctime(file_path)))\n",
    "print('{:30s}: {}'.format('getmtime 修改时间', os.path.getmtime(file_path)))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "File:   ./----.ipynb\n",
      "File:   ./Numpy.ipynb\n",
      "File:   ./Python0.ipynb\n",
      "File:   ./python笔记.ipynb\n",
      "File:   ./Python高阶.ipynb\n",
      "File:   ./test.csv\n",
      "File:   ./test.npy\n",
      "File:   ./.ipynb_checkpoints/-----checkpoint.ipynb\n",
      "File:   ./.ipynb_checkpoints/Numpy-checkpoint.ipynb\n",
      "File:   ./.ipynb_checkpoints/Python0-checkpoint.ipynb\n",
      "File:   ./.ipynb_checkpoints/python笔记-checkpoint.ipynb\n",
      "File:   ./.ipynb_checkpoints/Python高阶-checkpoint.ipynb\n",
      "File:   ./.ipynb_checkpoints/test-checkpoint.csv\n",
      "File:   ./_temp/json_demo.json\n",
      "File:   ./_temp/test.pickle\n",
      "File:   ./_temp/test.txt\n",
      "Folder: ./.ipynb_checkpoints\n",
      "Folder: ./_temp\n",
      "Folder: ./_temp/.ipynb_checkpoints\n",
      "['rename-python笔记.ipynb']\n",
      "['.ipynb_checkpoints', 'json_demo.json', 'test.pickle', 'test.txt']\n",
      "当前路径 /tf/PythonStudyNotes/_temp\n",
      "当前路径 /tf/PythonStudyNotes\n"
     ]
    }
   ],
   "source": [
    "import shutil\n",
    "# os.walk  循环查看文件夹中各级文件\n",
    "for root, folder, files in os.walk('.'):\n",
    "    for file_i in files:\n",
    "        print('File:   {}/{}'.format(root,  file_i))\n",
    "\n",
    "for root, folder, files in os.walk('.'):\n",
    "    for file_i in folder:\n",
    "        print('Folder: {}/{}'.format(root,  file_i))\n",
    "        \n",
    "# os.makedirs  创建文件夹\n",
    "os.makedirs('./_temp/_os-temp', exist_ok=True)\n",
    "# 文件复制及重命名\n",
    "shutil.copy('./python笔记.ipynb', './_temp/_os-temp/copy-python笔记.ipynb')\n",
    "shutil.move('./_temp/_os-temp/copy-python笔记.ipynb', './_temp/_os-temp/rename-python笔记.ipynb')\n",
    "# os.listdir 查看文件夹中文件\n",
    "print(os.listdir('./_temp/_os-temp'))\n",
    "# 删除文件\n",
    "shutil.rmtree('./_temp/_os-temp')\n",
    "# os.listdir 查看文件夹中文件\n",
    "print(os.listdir('./_temp'))\n",
    "\n",
    "# 当前目录\n",
    "raw_path = os.getcwd()\n",
    "# 更改当前工作目录\n",
    "os.chdir('./_temp')\n",
    "print('当前路径', os.getcwd())\n",
    "os.chdir(raw_path)\n",
    "print('当前路径', os.getcwd())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 错误与异常"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "------------------------------ 无异常\n",
      "1：Try \n",
      "3: Else\n",
      "4: Finally\n",
      "------------------------------ 异常\n",
      "1：Try \n",
      "2: Except  MemoryError()\n",
      "4: Finally\n",
      "------------------------------ 断言\n"
     ]
    },
    {
     "ename": "AssertionError",
     "evalue": "断言语句 False",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mAssertionError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-21-96c7164d5cb3>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m     27\u001b[0m \u001b[0;31m# 断言语句\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     28\u001b[0m \u001b[0;32massert\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m==\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'断言语句 True'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 29\u001b[0;31m \u001b[0;32massert\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m==\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'断言语句 False'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mAssertionError\u001b[0m: 断言语句 False"
     ]
    }
   ],
   "source": [
    "# ###################################\n",
    "print('-'*30, '无异常')\n",
    "try:\n",
    "    print('1：Try ')\n",
    "except Exception as error:\n",
    "    print('2: Except  {}'.format(repr(error)))\n",
    "else:\n",
    "    print('3: Else')\n",
    "finally:\n",
    "    print('4: Finally')\n",
    "    \n",
    "# ###################################\n",
    "print('-'*30, '异常')\n",
    "try:\n",
    "    print('1：Try ')\n",
    "    # 异常触发\n",
    "    raise MemoryError  # NameError、KeyboardInterrupt\n",
    "except Exception as error:\n",
    "    print('2: Except  {}'.format(repr(error)))\n",
    "else:\n",
    "    print('3: Else')\n",
    "finally:\n",
    "    print('4: Finally')\n",
    "    \n",
    "# ##################################\n",
    "print('-'*30, '断言')\n",
    "# 断言语句\n",
    "assert 1==1, '断言语句 True'\n",
    "assert 1==0, '断言语句 False'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "嵌套函数  : 20\n",
      "lambda函数: 20\n",
      "闭包函数  : 2\n",
      "闭包函数  : 3\n",
      "map   :  [1, 4, 9, 16, 25]\n",
      "filter:  [2, 4, 6, 8, 10]\n"
     ]
    }
   ],
   "source": [
    "# 嵌套函数\n",
    "def fun(a=1):\n",
    "    def sub_fun(b):\n",
    "        return a*b\n",
    "    return sub_fun\n",
    "    \n",
    "print('嵌套函数  :', fun(10)(2))\n",
    "\n",
    "# lambda 函数\n",
    "fun = lambda a,b=1: a*b\n",
    "print('lambda函数:', fun(10, 2))\n",
    "\n",
    "# 闭包\n",
    "def counter(start=1):\n",
    "    count = [start]\n",
    "    def add_1():\n",
    "#         print(count)\n",
    "        count[0] += 1\n",
    "        return count[0]\n",
    "    return add_1\n",
    "\n",
    "count = counter(start=1)\n",
    "print('闭包函数  :', count())\n",
    "print('闭包函数  :', count())\n",
    "\n",
    "# 内建函数 map filiter 返回迭代器对象\n",
    "# map(function, iterable, ...) 第一个参数 function 以参数序列中的每一个元素调用 function 函数，返回包含每次 function 函数返回值的新列表\n",
    "print('map   : ', list(map(lambda x: x ** 2, [1, 2, 3, 4, 5])))  # 使用 lambda 匿名函数 每个数取平方\n",
    " \n",
    "# filter(function, iterable)  该接收两个参数，第一个为函数，第二个为序列，序列的每个元素作为参数传递给函数进行判，然后返回 True 或 False，最后将返回 True 的元素放到新列表中\n",
    "print('filter: ', list(filter(lambda x: x%2==0, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])))  # 筛选偶数\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 生成器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "1\n",
      "2\n",
      "3\n",
      "4\n"
     ]
    }
   ],
   "source": [
    "# 生成器\n",
    "def iteration(num):\n",
    "    for x in range(num):\n",
    "        yield x\n",
    "\n",
    "# 调用         \n",
    "for x_i in iteration(5):\n",
    "    print(x_i)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 装饰器\n",
    "https://mp.weixin.qq.com/s/qyxHHQKwFgAKUjiovTGEAg"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "装饰器  开始执行 add 函数:\n",
      "------------------------------\n",
      "2 + 3 = 5\n",
      "------------------------------\n",
      "装饰器  执行结束。用时 0.00122 Sec\n"
     ]
    }
   ],
   "source": [
    "# 不带参数装饰器   这是装饰器函数，参数 func 是被装饰的函数\n",
    "def logger(func):\n",
    "    def wrapper(*args, **kw):\n",
    "        print('装饰器  开始执行 {} 函数:'.format(func.__name__))\n",
    "        t1=time.time()\n",
    "        print('-'*30)\n",
    "        # 真正执行的是这行。\n",
    "        func(*args, **kw)\n",
    "        print('-'*30)\n",
    "        print('装饰器  执行结束。用时 {:.5f} Sec'.format(time.time() - t1))\n",
    "    return wrapper\n",
    "\n",
    "@logger\n",
    "def add(x, y):\n",
    "    print('{} + {} = {}'.format(x, y, x+y))\n",
    "    \n",
    "add(2,3)    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "你好!\n",
      "------------------------------\n",
      "xiaoming\n",
      "------------------------------\n",
      "\n",
      "hello.\n",
      "------------------------------\n",
      "jack\n",
      "------------------------------\n"
     ]
    }
   ],
   "source": [
    "# 带参数的装饰器\n",
    "def say_hello(contry):\n",
    "    def wrapper(func):\n",
    "        def deco(*args, **kwargs):\n",
    "            if contry == \"china\":\n",
    "                print(\"\\n你好!\")\n",
    "            elif contry == \"america\":\n",
    "                print('\\nhello.')\n",
    "            else:\n",
    "                return\n",
    "            \n",
    "            print('-'*30)\n",
    "            # 真正执行函数的地方\n",
    "            func(*args, **kwargs)\n",
    "            print('-'*30)\n",
    "        \n",
    "        return deco\n",
    "    return wrapper\n",
    "\n",
    "# 小明，中国人\n",
    "@say_hello(\"china\")\n",
    "def xiaoming():\n",
    "    print(sys._getframe().f_code.co_name)\n",
    "\n",
    "# jack，美国人\n",
    "@say_hello(\"america\")\n",
    "def jack():\n",
    "    print(sys._getframe().f_code.co_name)\n",
    "\n",
    "xiaoming()\n",
    "jack()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 单例模式装饰器\n",
    "def singleton(cls):\n",
    "    # 单下划线的作用是这个变量只能在当前模块里访问,仅仅是一种提示作用\n",
    "    # 创建一个字典用来保存类的实例对象\n",
    "    _instance = {}\n",
    "\n",
    "    def _singleton(*args, **kwargs):\n",
    "        # 先判断这个类有没有对象\n",
    "        if cls not in _instance:\n",
    "            _instance[cls] = cls(*args, **kwargs)  # 创建一个对象,并保存到字典当中\n",
    "        else:\n",
    "            print('已创建，直接调用。')\n",
    "        # 将实例对象返回\n",
    "        return _instance[cls]\n",
    "\n",
    "    return _singleton"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Demo str1\n",
      "20201102193535\n",
      "ID:  2066959538776\n",
      "--------------------------------\n",
      "已创建，直接调用。\n",
      "Demo str2\n",
      "20201102193535\n",
      "ID:  2066959538776\n"
     ]
    }
   ],
   "source": [
    "# 单例模式，保证不生成多个类\n",
    "@singleton\n",
    "class ClassDemo(object):\n",
    "    V = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))\n",
    "\n",
    "    def __init__(self):\n",
    "        self.demo = 'Demo'\n",
    "\n",
    "    def print(self, str1):\n",
    "        print(self.demo, str1)\n",
    "        print(self.V)\n",
    "\n",
    "\n",
    "c1 = ClassDemo()\n",
    "c1.print('str1')\n",
    "print('ID: ', id(c1))\n",
    "\n",
    "print('--------------------------------')\n",
    "c2 = ClassDemo()\n",
    "c2.print('str2')\n",
    "print('ID: ', id(c2))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Demo str1\n",
      "20201102193549\n",
      "ID:  2066959538720\n",
      "--------------------------------\n",
      "Demo str2\n",
      "20201102193549\n",
      "ID:  2066959539280\n"
     ]
    }
   ],
   "source": [
    "# 普通模式，每次创建新建一个类\n",
    "class ClassDemo(object):\n",
    "    V = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))\n",
    "\n",
    "    def __init__(self):\n",
    "        self.demo = 'Demo'\n",
    "\n",
    "    def print(self, str1):\n",
    "        print(self.demo, str1)\n",
    "        print(self.V)\n",
    "\n",
    "\n",
    "c1 = ClassDemo()\n",
    "c1.print('str1')\n",
    "print('ID: ', id(c1))\n",
    "\n",
    "print('--------------------------------')\n",
    "c2 = ClassDemo()\n",
    "c2.print('str2')\n",
    "print('ID: ', id(c2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 类"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "创建时间  16:32:23\n",
      "version:  V 16:32:23\n",
      "实例化  16:32:23\n",
      "\n",
      "version:  V 16:32:23\n",
      "实例化  16:32:23\n",
      "类说明文档：\n",
      "    自定义类说明\n",
      "    \n",
      "类方法调用：10\n",
      "类方法调用：call\n",
      "类属性读取：V 16:32:23\n",
      "类属性修改：None\n",
      "类属性读取：V test\n",
      "类默认属性：['__call__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'use', 'version', 'x']\n",
      "实例对应类：<class '__main__.ClassDemo'>\n",
      "所在模块  ：__main__\n",
      "实例属性  ：{'x': 10, 'version': 'V test'}\n",
      "实例属性  ：{'x': 10, 'version': 'V test'}\n"
     ]
    }
   ],
   "source": [
    "# 创建类函数\n",
    "class ClassDemo(object):  # 类定义\n",
    "    '''\n",
    "    自定义类说明\n",
    "    '''\n",
    "    print('创建时间  {}'.format(time.strftime('%H:%M:%S', time.localtime(time.time()))))\n",
    "    # 静态数据  每次实例化时此处属性保持不变\n",
    "    version = time.strftime('V %H:%M:%S', time.localtime(time.time())) \n",
    "    \n",
    "    def __init__(self):  # 定义构造器\n",
    "        print('version: ', self.version)\n",
    "        print('实例化  {}'.format(time.strftime('%H:%M:%S', time.localtime(time.time()))))\n",
    "    \n",
    "    def use(self, x):  # 定义方法\n",
    "        self.x = x\n",
    "        return x\n",
    "        \n",
    "    def __call__(self):\n",
    "        return 'call'\n",
    "        \n",
    "ClassDemo.version\n",
    "\n",
    "demo1 = ClassDemo()   \n",
    "# time.sleep(2)\n",
    "print()\n",
    "demo2 = ClassDemo()\n",
    "\n",
    "# 类 说明文档\n",
    "print('类说明文档：{}'.format(demo2.__doc__))\n",
    "# 类 方法调用\n",
    "print('类方法调用：{}'.format(demo2.use(10)))\n",
    "# 类 方法调用\n",
    "print('类方法调用：{}'.format(demo2()))\n",
    "# 类属性读取、修改\n",
    "print('类属性读取：{}'.format(demo2.version))\n",
    "print('类属性修改：{}'.format(setattr(demo2, 'version', 'V test')))\n",
    "print('类属性读取：{}'.format(getattr(demo2, 'version')))\n",
    "\n",
    "# 类默认属性\n",
    "print('类默认属性：{}'.format(dir(demo2)))\n",
    "\n",
    "print('实例对应类：{}'.format(demo2.__class__))\n",
    "print('所在模块  ：{}'.format(demo2.__module__))\n",
    "print('实例属性  ：{}'.format(demo2.__dict__))\n",
    "print('实例属性  ：{}'.format(vars(demo2)))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Num:1\n",
      "Num:2\n",
      "Num:3\n",
      "Num:1\n"
     ]
    }
   ],
   "source": [
    "# 利用静态成员记录实例数量\n",
    "class InstCt(object):\n",
    "    count = 0\n",
    "\n",
    "    def __init__(self):\n",
    "        InstCt.count += 1  # 创建实例时 + 1\n",
    "\n",
    "    def __del__(self):\n",
    "        InstCt.count -= 1  # 删除实例时 -1\n",
    "\n",
    "    @staticmethod\n",
    "    def how_many(): # 打印当前实例数量\n",
    "        return 'Num:{}'.format(InstCt.count)\n",
    "\n",
    "a = InstCt()\n",
    "print(a.how_many())\n",
    "b = InstCt()\n",
    "print(a.how_many())\n",
    "c = InstCt()\n",
    "print(a.how_many())\n",
    "del c, b\n",
    "print(a.how_many())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Calling parent method\n",
      "This's  parent\n",
      "\n",
      "Calling parent method\n",
      "Calling child method\n",
      "This's  parent\n",
      "This's  parent\n",
      "This's  child\n"
     ]
    }
   ],
   "source": [
    "# 类继承   super(Child, self).name()  # 调用父类方法\n",
    "class Parent(object):  # 定义父类\n",
    "    def parent_method(self):\n",
    "        print('Calling parent method')\n",
    "\n",
    "    def name(self):\n",
    "        print(\"This's  parent\")\n",
    "\n",
    "\n",
    "class Child(Parent):  # 定义子类\n",
    "    def child_method(self):\n",
    "        print('Calling child method')\n",
    "\n",
    "    def name(self):  # 父类的name 方法会被覆盖\n",
    "        Parent.name(self)          # 调用父类方法\n",
    "        super(Child, self).name()  # 调用父类方法\n",
    "        print(\"This's  child\")\n",
    "        \n",
    "p = Parent()\n",
    "p.parent_method()\n",
    "p.name()\n",
    "\n",
    "print()\n",
    "c = Child()\n",
    "c.parent_method() # 调用自身方法\n",
    "c.child_method()  # 子类调用父类方法\n",
    "c.name()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "C1 arg_c: arg_c\n",
      "   Call arg_a: arg_a\n",
      "C2 arg_c: arg_c\n",
      "C2 arg_a: arg_a\n",
      "\n",
      "str(cc)\n",
      "C dir : arg_a、arg_c、fun_a1、fun_b1、fun_b2\n",
      "\n",
      "cc.fun_b2()\n",
      "   Call fun_b2:  C dir : arg_a、arg_c、fun_a1、fun_b1、fun_b2\n",
      "\n",
      "cc.fun_b1()\n",
      "AttributeError(\"'C' object has no attribute 'arg_b'\",)\n"
     ]
    }
   ],
   "source": [
    "# C 继承 A、B\n",
    "class A:\n",
    "    def __init__(self, arg_a='a'):\n",
    "        self.arg_a = arg_a\n",
    "        print('   Call arg_a:', self.arg_a)\n",
    "\n",
    "    def fun_a1(self):\n",
    "        print('   Call fun_a1 ', self)\n",
    "\n",
    "    def __repr__(self):\n",
    "        return 'A dir : {}'.format('、'.join([d_i for d_i in dir(self) if not d_i.startswith('__')]))\n",
    "\n",
    "\n",
    "class B:\n",
    "    def __init__(self, arg_b='b'):\n",
    "        self.arg_b = arg_b\n",
    "        print('   Call arg_b:', arg_b)\n",
    "\n",
    "    def fun_b1(self):\n",
    "        print('   Call fun_b1 arg_b:', self.arg_b)\n",
    "\n",
    "    def fun_b2(self):\n",
    "        print('   Call fun_b2: ', self)\n",
    "\n",
    "    def __repr__(self):\n",
    "        return 'B dir : {}'.format('、'.join([d_i for d_i in dir(self) if not d_i.startswith('__')]))\n",
    "\n",
    "\n",
    "class C(A, B):\n",
    "    \"\"\"\n",
    "    有相同函数的优先继承 A\n",
    "    \"\"\"\n",
    "\n",
    "    def __init__(self, arg_c, *args, **kwargs):\n",
    "        print('C1 arg_c:', arg_c)\n",
    "        # print('C1 arg_a:', self.arg_a)  # 未调用父类属性，将出现异常\n",
    "\n",
    "        super(C, self).__init__(*args, **kwargs)\n",
    "        print('C2 arg_c:', arg_c)\n",
    "        print('C2 arg_a:', self.arg_a)\n",
    "        # print('C2 arg_b:', self.arg_b)  # __init__ 中只继承了 A\n",
    "\n",
    "        self.arg_c = arg_c\n",
    "\n",
    "    def __repr__(self):\n",
    "        return 'C dir : {}'.format('、'.join([d_i for d_i in dir(self) if not d_i.startswith('__')]))\n",
    "\n",
    "\n",
    "cc = C(arg_a='arg_a', arg_c='arg_c')\n",
    "\n",
    "print('\\nstr(cc)')\n",
    "print(cc)\n",
    "\n",
    "print('\\ncc.fun_b2()')\n",
    "cc.fun_b2()\n",
    "print('\\ncc.fun_b1()')\n",
    "try:\n",
    "    cc.fun_b1()  # B 类的 __init__ 未被继承，无法调用 init 中的self.arg_b\n",
    "except Exception as error:\n",
    "    print(repr(error))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Init A() \n",
      "   A Call arg_a: a\n",
      "\n",
      "Init B() \n",
      "   A Call arg_a: a\n",
      "   B Call arg_b: b\n",
      "\n",
      "Init C() \n",
      "   A Call arg_a: a\n",
      "   B Call arg_b: b\n",
      "   C Call arg_c: c\n",
      "   fun_c1 : C dir : arg_a、arg_b、arg_c、fun_a1、fun_b1、fun_c1\n",
      "\n",
      "A dir : arg_a、fun_a1\n",
      "B dir : arg_a、arg_b、fun_a1、fun_b1\n",
      "C dir : arg_a、arg_b、arg_c、fun_a1、fun_b1、fun_c1\n"
     ]
    }
   ],
   "source": [
    "# C 继承 B , B 继承 A\n",
    "class A:\n",
    "    def __init__(self, arg_a='a'):\n",
    "        self.arg_a = arg_a\n",
    "        print('   A Call arg_a:', self.arg_a)\n",
    "\n",
    "    def fun_a1(self):\n",
    "        print('   fun_a1: ', self)\n",
    "\n",
    "    def __repr__(self):\n",
    "        return 'A dir : {}'.format('、'.join([d_i for d_i in dir(self) if not d_i.startswith('__')]))\n",
    "\n",
    "\n",
    "class B(A):\n",
    "    def __init__(self, arg_b='b'):\n",
    "        super(B, self).__init__()\n",
    "        self.arg_b = arg_b\n",
    "        print('   B Call arg_b:', arg_b)\n",
    "\n",
    "    def fun_b1(self):\n",
    "        print('   fun_b1 :', self)\n",
    "\n",
    "    def __repr__(self):\n",
    "        return 'B dir : {}'.format('、'.join([d_i for d_i in dir(self) if not d_i.startswith('__')]))\n",
    "\n",
    "\n",
    "class C(B):\n",
    "    def __init__(self, arg_c='c'):\n",
    "        super(C, self).__init__()\n",
    "        self.arg_c = arg_c\n",
    "        print('   C Call arg_c:', arg_c)\n",
    "\n",
    "    def fun_c1(self):\n",
    "        print('   fun_c1 :', self)\n",
    "\n",
    "    def __repr__(self):\n",
    "        return 'C dir : {}'.format('、'.join([d_i for d_i in dir(self) if not d_i.startswith('__')]))\n",
    "\n",
    "\n",
    "print('Init A() ')\n",
    "a = A()\n",
    "print('\\nInit B() ')\n",
    "b = B()\n",
    "print('\\nInit C() ')\n",
    "c = C()\n",
    "c.fun_c1()\n",
    "\n",
    "print('')\n",
    "print(a)\n",
    "print(b)\n",
    "print(c)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "A().fun()\n",
      "   Call arg_a: a\n",
      "NotImplementedError()\n",
      "\n",
      "B().fun()\n",
      "   Call arg_a: a\n",
      "   Call arg_b: b\n",
      "   Call B fun:  B dir : arg_a、arg_b、fun\n",
      "\n",
      "C().fun()\n",
      "   Call arg_a: a\n",
      "   Call arg_b: b\n",
      "   Call arg_c: c\n",
      "   Call C fun:  C dir : arg_a、arg_b、arg_c、fun\n"
     ]
    }
   ],
   "source": [
    "# NotImplementedError  预留函数接口\n",
    "class A:\n",
    "    def __init__(self, arg_a='a'):\n",
    "        self.arg_a = arg_a\n",
    "        print('   Call arg_a:', self.arg_a)\n",
    "\n",
    "    # 预留函数接口，子类调用时实现此函数\n",
    "    def fun(self):\n",
    "        raise NotImplementedError\n",
    "\n",
    "    def __repr__(self):\n",
    "        return 'A dir : {}'.format('、'.join([d_i for d_i in dir(self) if not d_i.startswith('__')]))\n",
    "\n",
    "\n",
    "class B(A):\n",
    "    def __init__(self, arg_b='b', *args, **kwargs):\n",
    "        super(B, self).__init__(*args, **kwargs)\n",
    "        self.arg_b = arg_b\n",
    "        print('   Call arg_b:', arg_b)\n",
    "\n",
    "    # 实现基类的 fun 函数 \n",
    "    def fun(self):\n",
    "        print('   Call B fun: ', self)\n",
    "\n",
    "    def __repr__(self):\n",
    "        return 'B dir : {}'.format('、'.join([d_i for d_i in dir(self) if not d_i.startswith('__')]))\n",
    "\n",
    "\n",
    "class C(B):\n",
    "    def __init__(self, arg_c='c', *args, **kwargs):\n",
    "        super(C, self).__init__(*args, **kwargs)\n",
    "        self.arg_c = arg_c\n",
    "        print('   Call arg_c:', arg_c)\n",
    "\n",
    "    # 替换 类函数 B 中的 fun 函数 \n",
    "    def fun(self):\n",
    "        print('   Call C fun: ', self)\n",
    "\n",
    "    def __repr__(self):\n",
    "        return 'C dir : {}'.format('、'.join([d_i for d_i in dir(self) if not d_i.startswith('__')]))\n",
    "\n",
    "\n",
    "print('\\nA().fun()')\n",
    "try:\n",
    "    A().fun()\n",
    "except Exception as error:\n",
    "    print(repr(error))\n",
    "\n",
    "print('\\nB().fun()')\n",
    "try:\n",
    "    B().fun()\n",
    "except Exception as error:\n",
    "    print(repr(error))\n",
    "\n",
    "print('\\nC().fun()')\n",
    "try:\n",
    "    C().fun()\n",
    "except Exception as error:\n",
    "    print(repr(error))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "dir : _images、_labels、images、labels\n",
      "1\n",
      "2\n"
     ]
    },
    {
     "ename": "AttributeError",
     "evalue": "can't set attribute",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-4-46475f6a3eab>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m     19\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0ml\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlabels\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     20\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 21\u001b[1;33m \u001b[0ml\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mimages\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;36m10\u001b[0m  \u001b[1;31m# 无法直接修改\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mAttributeError\u001b[0m: can't set attribute"
     ]
    }
   ],
   "source": [
    "class DataSet(object):\n",
    "    def __init__(self):\n",
    "        self._images = 1\n",
    "        self._labels = 2  # 定义属性的名称\n",
    "\n",
    "    @property\n",
    "    def images(self):  # 方法加入@property后，这个方法相当于一个属性，这个属性可以让用户进行使用，而且用户有没办法随意修改。\n",
    "        return self._images\n",
    "\n",
    "    def labels(self):\n",
    "        return self._labels\n",
    "\n",
    "    def __repr__(self):\n",
    "        return 'dir : {}'.format('、'.join([d_i for d_i in dir(self) if not d_i.startswith('__')]))\n",
    "    \n",
    "l = DataSet()\n",
    "print(l)\n",
    "print(l.images)\n",
    "print(l.labels())\n",
    "\n",
    "l.images = 10  # 无法直接修改"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 正则表达式\n",
    "https://www.runoob.com/python3/python3-reg-expressions.html  \n",
    "`^`\t匹配字符串的开头  \n",
    "`$`\t匹配字符串的末尾。  \n",
    "`.`\t匹配任意字符，除了换行符，当re.DOTALL标记被指定时，则可以匹配包括换行符的任意字符。  \n",
    "`[...]`\t用来表示一组字符,单独列出：[amk] 匹配 'a'，'m'或'k'  \n",
    "`[^...]`\t不在[]中的字符：[^abc] 匹配除了a,b,c之外的字符。  \n",
    "`re*`\t匹配0个或多个的表达式。  \n",
    "`re+`\t匹配1个或多个的表达式。  \n",
    "`re?`\t匹配0个或1个由前面的正则表达式定义的片段，非贪婪方式  \n",
    "`re{ n}`\t匹配n个前面表达式。例如，\"o{2}\"不能匹配\"Bob\"中的\"o\"，但是能匹配\"food\"中的两个o。  \n",
    "`re{ n,}`\t精确匹配n个前面表达式。例如，\"o{2,}\"不能匹配\"Bob\"中的\"o\"，但能匹配\"foooood\"中的所有o。\"o{1,}\"等价于\"o+\"。\"o{0,}\"则等价于\"o*\"。  \n",
    "`re{ n, m}`\t匹配 n 到 m 次由前面的正则表达式定义的片段，贪婪方式  \n",
    "`a| b`\t匹配a或b    \n",
    "`(re)`\t匹配括号内的表达式，也表示一个组  \n",
    "`(?imx)`\t正则表达式包含三种可选标志：i, m, 或 x 。只影响括号中的区域。  \n",
    "`(?-imx)`\t正则表达式关闭 i, m, 或 x 可选标志。只影响括号中的区域。  \n",
    "`(?: re)`\t类似 (...), 但是不表示一个组   \n",
    "`(?imx: re)`\t在括号中使用i, m, 或 x 可选标志  \n",
    "`(?-imx: re)`\t在括号中不使用i, m, 或 x 可选标志  \n",
    "`(?#...)`\t注释.  \n",
    "`(?= re)`\t前向肯定界定符。如果所含正则表达式，以 ... 表示，在当前位置成功匹配时成功，否则失败。但一旦所含表达式已经尝试，匹配引擎根本没有提高；模式的剩余部分还要尝试界定符的右边。  \n",
    "`(?! re)`\t前向否定界定符。与肯定界定符相反；当所含表达式不能在字符串当前位置匹配时成功。  \n",
    "`(?> re)`\t匹配的独立模式，省去回溯。  \n",
    "`\\w`\t匹配数字字母下划线  \n",
    "`\\W`\t匹配非数字字母下划线  \n",
    "`\\s`\t匹配任意空白字符，等价于 [\\t\\n\\r\\f]。  \n",
    "`\\S`\t匹配任意非空字符  \n",
    "`\\d`\t匹配任意数字，等价于 [0-9]。  \n",
    "`\\D`\t匹配任意非数字  \n",
    "`\\A`\t匹配字符串开始   \n",
    "`\\Z`\t匹配字符串结束，如果是存在换行，只匹配到换行前的结束字符串。  \n",
    "`\\z`\t匹配字符串结束  \n",
    "`\\G`\t匹配最后匹配完成的位置。  \n",
    "`\\b`\t匹配一个单词边界，也就是指单词和空格间的位置。例如， 'er\\b' 可以匹配\"never\" 中的 'er'，但不能匹配 \"verb\" 中的 'er'。  \n",
    "`\\B`\t匹配非单词边界。'er\\B' 能匹配 \"verb\" 中的 'er'，但不能匹配 \"never\" 中的 'er'。  \n",
    "`\\n, \\t,` 等。\t匹配一个换行符。匹配一个制表符, 等  \n",
    "`\\1...\\9`\t匹配第n个分组的内容。  \n",
    "`\\10`\t匹配第n个分组的内容，如果它经匹配。否则指的是八进制字符码的表达式。  \n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['Hello', 'World', 'Wide', 'Web', '711', '89M']\n",
      "[('13', '3', '65', '99', '-0.87')]\n",
      "你好--中国-Hello-word-China\n",
      "['你好', '', '', '中国', 'Hello', 'word', 'China']\n",
      "['12312313-31-1']\n"
     ]
    }
   ],
   "source": [
    "import re\n",
    "# help(re)\n",
    "\n",
    "# 提取数字、字母\n",
    "pattern = re.compile(r'([a-z0-9]+)', re.I)   # re.I 表示忽略大小写\n",
    "print(pattern.findall('Hello World    Wide Web 711 !@#%89M&'))\n",
    "\n",
    "# 提取特定数值\n",
    "pattern = re.compile('Box:\\\\[(\\d+),(\\d+),(\\d+),(\\d+)\\\\], Pro:(-*[0-9]+(?:\\.[0-9]{1,2})?)')    # '()' 提取数据   '(?:)' 不提取此处数据\n",
    "print(pattern.findall('Box:[13,3,65,99], Pro:-0.87'))\n",
    "\n",
    "# 替换、分隔拆分\n",
    "pattern = re.compile('[-,\\.|，\\s]', re.S)   # \\ \n",
    "print(re.sub(pattern, '-', '你好，\\n中国.Hello|word.China'))\n",
    "print(re.split(pattern, '你好，\\n 中国.Hello|word.China'))\n",
    "\n",
    "# 贪婪匹配\n",
    "pattern = re.compile('.+?(\\d+-\\d+-\\d)')    #  .+?\n",
    "print(pattern.findall('adfasf:12312313-31-1'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 多线程编程\n",
    "多线程适用于 `IO密集型` 程序;    \n",
    "多进程适用于 `计算密集型` 程序(具体程序参考https://gitee.com/STUVincent_vincent/NewWordDiscovery)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "Start  loop 0  at Wed Jan  1 16:32:29 2020\n",
      "1\n",
      "Start  loop 1  at Wed Jan  1 16:32:29 2020\n",
      "2\n",
      "Start  loop 2  at Wed Jan  1 16:32:29 2020\n",
      "3\n",
      "Start  loop 3  at Wed Jan  1 16:32:29 2020\n",
      "4\n",
      "Start  loop 4  at Wed Jan  1 16:32:29 2020\n",
      "线程创建及开启完毕，等待处理。。。\n",
      "0 True\n",
      "Finish loop 1  at Wed Jan  1 16:32:34 2020\n",
      "Finish loop 0  at Wed Jan  1 16:32:34 2020\n",
      "0 False\n",
      "1 False\n",
      "1 False\n",
      "2 True\n",
      "Finish loop 2  at Wed Jan  1 16:32:34 2020\n",
      "Finish loop 3  at Wed Jan  1 16:32:34 2020\n",
      "2 False\n",
      "3 False\n",
      "3 Finish loop 4  at Wed Jan  1 16:32:34 2020\n",
      "False\n",
      "4 False\n",
      "4 False\n",
      "所有线程处理结束！总用时： 5.0 Sec\n"
     ]
    }
   ],
   "source": [
    "import threading\n",
    "\n",
    "# 子线程处理程序 \n",
    "def loop(nloop, nsec):\n",
    "    print('Start  loop {}  at {}'.format(nloop, time.ctime()))\n",
    "    time.sleep(nsec)\n",
    "    print('Finish loop {}  at {}'.format(nloop, time.ctime()))\n",
    "    \n",
    "# ####################################################################\n",
    "start_time = time.time()\n",
    "# 线程池\n",
    "threads = list()\n",
    "\n",
    "# 创建及开启线程\n",
    "for i in range(5):\n",
    "    print(i)\n",
    "    t = threading.Thread(target=loop, args=(i, 5))  #创建线程\n",
    "    t.start()  # 开启线程\n",
    "    threads.append(t)  # 放入线程池\n",
    "\n",
    "print('线程创建及开启完毕，等待处理。。。')\n",
    "\n",
    "# 等待线程结束 \n",
    "for i in range(5):\n",
    "    print(i, threads[i].isAlive())\n",
    "    threads[i].join(timeout=10)   # 程序挂起 直到线程结束或 timeout\n",
    "    print(i, threads[i].isAlive())\n",
    "    \n",
    "print('所有线程处理结束！总用时： {:.1f} Sec'.format(time.time() - start_time))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "Start  fib-0  at Wed Jan  1 16:32:34 20201\n",
      "\n",
      "Start  fib-1  at Wed Jan  1 16:32:34 2020\n",
      "2\n",
      "Start  fib-2  at Wed Jan  1 16:32:34 2020\n",
      "3\n",
      "Start  fib-3  at Wed Jan  1 16:32:34 2020\n",
      "4\n",
      "Start  fib-4  at Wed Jan  1 16:32:34 2020\n",
      "线程创建及开启完毕，等待处理。。。\n",
      "0 True\n",
      "Finish fib-4  at Wed Jan  1 16:32:36 2020Finish fib-0  at Wed Jan  1 16:32:36 2020\n",
      "0\n",
      " Finish fib-1  at Wed Jan  1 16:32:36 2020\n",
      "False\n",
      "1 True\n",
      "Finish fib-2  at Wed Jan  1 16:32:36 2020\n",
      "1 False\n",
      "2 False\n",
      "2 False\n",
      "3 True\n",
      "Finish fib-3  at Wed Jan  1 16:32:36 2020\n",
      "3 False\n",
      "4 False\n",
      "4 False\n",
      "\n",
      "Result:  \n",
      "0 : 1346269\n",
      "1 : 1346269\n",
      "2 : 1346269\n",
      "3 : 1346269\n",
      "4 : 1346269\n",
      "所有线程处理结束！总用时： 2.1 Sec\n"
     ]
    }
   ],
   "source": [
    "import threading\n",
    "\n",
    "# 创建多线程处理函数\n",
    "class MyThread(threading.Thread):\n",
    "    \n",
    "    def __init__(self, func, args, name=''):\n",
    "        threading.Thread.__init__(self)\n",
    "        self.func=func\n",
    "        self.args=args\n",
    "        self.name=name\n",
    "    \n",
    "    def run(self):\n",
    "        print('Start  {}  at {}'.format(self.name, time.ctime()))\n",
    "        self.res = self.func(self.args)\n",
    "        print('Finish {}  at {}'.format(self.name, time.ctime()))\n",
    "    \n",
    "    def get_result(self):\n",
    "        return self.res\n",
    "    \n",
    "# 线程核心函数    \n",
    "def fib(x):\n",
    "    if x<2: \n",
    "        return 1\n",
    "    else:\n",
    "        return fib(x-1) + fib(x-2)\n",
    "    \n",
    "# ####################################################################\n",
    "start_time = time.time()\n",
    "# 线程池\n",
    "threads = list()\n",
    "\n",
    "# 创建及开启线程\n",
    "for i in range(5):\n",
    "    print(i)\n",
    "    t = MyThread(fib, 30 ,'fib-{}'.format(i))\n",
    "    t.start()  # 开启线程\n",
    "    threads.append(t)  # 放入线程池\n",
    "\n",
    "print('线程创建及开启完毕，等待处理。。。')\n",
    "\n",
    "# 等待线程结束 \n",
    "for i, thread_i in enumerate(threads):\n",
    "    print(i, thread_i.isAlive())\n",
    "    thread_i.join(timeout=10)   # 程序挂起 直到线程结束或 timeout\n",
    "    print(i, thread_i.isAlive())\n",
    "       \n",
    "# 读取线程结果\n",
    "print('\\nResult:  ')\n",
    "for i, thread_i in enumerate(threads):\n",
    "    print('{} : {}'.format(i, thread_i.get_result()))\n",
    "\n",
    "print('所有线程处理结束！总用时： {:.1f} Sec'.format(time.time() - start_time))\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import threading\n",
    "from time import ctime, sleep\n",
    "\n",
    "\n",
    "# 带返回值多线程\n",
    "class MyThread(threading.Thread):\n",
    "\n",
    "    def __init__(self, func, args=()):\n",
    "        super(MyThread, self).__init__()\n",
    "        self.func = func  # 子进程函数\n",
    "        self.args = args  # 子进程函数入参\n",
    "        self.result = None  # 默认返回结果为 None\n",
    "\n",
    "    def run(self):\n",
    "        self.result = self.func(*self.args)\n",
    "\n",
    "    def get_result(self):\n",
    "        return self.result\n",
    "\n",
    "\n",
    "# 线程 1 主函数\n",
    "def loop_1(sleep_time):\n",
    "    print('loop_1 Start: {}'.format(ctime()))\n",
    "    sleep(sleep_time)\n",
    "    print('loop_1 Over.: {}'.format(ctime()))\n",
    "    return 'Loop_1- Sleep:{}'.format(sleep_time)\n",
    "\n",
    "\n",
    "# 线程 2 主函数\n",
    "def loop_2(sleep_time):\n",
    "    print('loop_2 Start: {}'.format(ctime()))\n",
    "    sleep(sleep_time)\n",
    "    print('loop_2 Over.: {}'.format(ctime()))\n",
    "    return 'Loop_2- Sleep:{}'.format(sleep_time)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 正常状态 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "loop_1 Start: Wed Mar 17 22:15:11 2021\n",
      "loop_2 Start: Wed Mar 17 22:15:11 2021\n",
      "\n",
      "t1 t2  Start Over.Wed Mar 17 22:15:11 2021\n",
      "loop_1 Over.: Wed Mar 17 22:15:12 2021\n",
      "loop_2 Over.: Wed Mar 17 22:15:16 2021\n",
      "t1 t2  All Over.\n",
      "t1: Loop_1- Sleep:1  Wed Mar 17 22:15:16 2021\n",
      "t2: Loop_2- Sleep:5  Wed Mar 17 22:15:16 2021\n"
     ]
    }
   ],
   "source": [
    "# 线程1\n",
    "t1 = MyThread(loop_1, args=(1,))\n",
    "# 线程2\n",
    "t2 = MyThread(loop_2, args=(5,))\n",
    "\n",
    "t1.start()\n",
    "t2.start()\n",
    "print('\\nt1 t2  Start Over.{}'.format(ctime()))\n",
    "\n",
    "t1.join(timeout=10)  # 程序挂起 直到线程结束或 timeout\n",
    "t2.join(timeout=10)  # 程序挂起 直到线程结束或 timeout\n",
    "\n",
    "print('t1 t2  All Over.')\n",
    "\n",
    "print(\"t1: {}  {}\".format(t1.get_result(), ctime()))\n",
    "print(\"t2: {}  {}\".format(t2.get_result(), ctime()))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "若在主线程中创建了子线程，当主线程结束时根据子线程daemon（设置thread.setDaemon(True)）属性值的不同可能会发生下面的两种情况之一：  \n",
    "1、如果某个子线程的daemon属性为False，主线程结束时会检测该子线程是否结束，如果该子线程还在运行，则主线程会等待它完成后再退出；  \n",
    "2、如果某个子线程的daemon属性为True，主线程运行结束时不对这个子线程进行检查而直接退出，同时所有daemon值为True的子线程将随主线程一起结束，而不论是否运行完成。  \n",
    "\n",
    "属性daemon的值默认为False，如果需要修改，必须在调用start()方法启动线程之前进行设置。 "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 线程TimeOut  daemon默认值False"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "loop_1 Start: Wed Mar 17 22:15:39 2021\n",
      "loop_2 Start: Wed Mar 17 22:15:39 2021\n",
      "t1 t2  Start Over.Wed Mar 17 22:15:39 2021\n",
      "\n",
      "loop_1 Over.: Wed Mar 17 22:15:40 2021\n",
      "t1 t2  All Over. Wed Mar 17 22:15:42 2021\n",
      "t1: Loop_1- Sleep:1  Wed Mar 17 22:15:42 2021\n",
      "t2: None  Wed Mar 17 22:15:42 2021\n",
      "loop_2 Over.: Wed Mar 17 22:15:44 2021\n"
     ]
    }
   ],
   "source": [
    "# 线程1\n",
    "t1 = MyThread(loop_1, args=(1,))\n",
    "# 线程2\n",
    "t2 = MyThread(loop_2, args=(5,))\n",
    "\n",
    "t1.setDaemon(False)\n",
    "t1.start()\n",
    "t2.setDaemon(False)\n",
    "t2.start()\n",
    "print('\\nt1 t2  Start Over.{}'.format(ctime()))\n",
    "\n",
    "t1.join(timeout=2)  # 程序挂起 直到线程结束或 timeout\n",
    "t2.join(timeout=2)  # 程序挂起 直到线程结束或 timeout\n",
    "\n",
    "print('t1 t2  All Over.', ctime())\n",
    "\n",
    "print(\"t1: {}  {}\".format(t1.get_result(), ctime()))\n",
    "print(\"t2: {}  {}\".format(t2.get_result(), ctime()))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 线程TimeOut  daemon值为True"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "loop_1 Start: Wed Mar 17 22:16:01 2021\n",
      "loop_2 Start: Wed Mar 17 22:16:01 2021\n",
      "t1 t2  Start Over.Wed Mar 17 22:16:01 2021\n",
      "\n",
      "loop_1 Over.: Wed Mar 17 22:16:02 2021\n",
      "t1 t2  All Over. Wed Mar 17 22:16:04 2021\n",
      "t1: Loop_1- Sleep:1  Wed Mar 17 22:16:04 2021\n",
      "t2: None  Wed Mar 17 22:16:04 2021\n",
      "loop_2 Over.: Wed Mar 17 22:16:06 2021\n"
     ]
    }
   ],
   "source": [
    "# 线程1\n",
    "t1 = MyThread(loop_1, args=(1,))\n",
    "# 线程2\n",
    "t2 = MyThread(loop_2, args=(5,))\n",
    "\n",
    "t1.setDaemon(True)\n",
    "t1.start()\n",
    "t2.setDaemon(True)\n",
    "t2.start()\n",
    "print('\\nt1 t2  Start Over.{}'.format(ctime()))\n",
    "\n",
    "t1.join(timeout=2)  # 程序挂起 直到线程结束或 timeout\n",
    "t2.join(timeout=2)  # 程序挂起 直到线程结束或 timeout\n",
    "\n",
    "print('t1 t2  All Over.', ctime())\n",
    "\n",
    "print(\"t1: {}  {}\".format(t1.get_result(), ctime()))\n",
    "print(\"t2: {}  {}\".format(t2.get_result(), ctime()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 后台监控线程。 在系统中可作为后台定时任务线程，如模型更新、心跳、服务监测等\n",
    "import time\n",
    "from datetime import datetime\n",
    "import threading\n",
    "\n",
    "# 后台监控进程\n",
    "class BackstageThread(threading.Thread):\n",
    "    def __init__(self):\n",
    "        threading.Thread.__init__(self)\n",
    "        self.stop_event = threading.Event()\n",
    "\n",
    "        # 运行状态标志位\n",
    "        self.flag = True\n",
    "\n",
    "        self.num = 1\n",
    "\n",
    "    def stop(self):\n",
    "        self.stop_event.set()\n",
    "\n",
    "    # 启动程序\n",
    "    def run(self):\n",
    "        # 循环监控，可使用定时器替换\n",
    "        while True:  # 可使用开关替换\n",
    "\n",
    "            if self.flag:\n",
    "                print('后台进程：{}   {}'.format(datetime.now().strftime(\"%Y-%m-%d %H:%M:%S\"), self.num))\n",
    "\n",
    "                self.num += 1\n",
    "                time.sleep(1)\n",
    "\n",
    "    def pause(self):\n",
    "        print('Pause!!!')\n",
    "        self.flag = False\n",
    "\n",
    "    def play(self):\n",
    "        print('Play !!!')\n",
    "        self.flag = True\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "后台进程：2020-11-05 20:49:42   1主进程: 0\n",
      "\n",
      "主进程: 1\n",
      "后台进程：2020-11-05 20:49:43   2\n",
      "主进程: 2\n",
      "后台进程：2020-11-05 20:49:44   3\n",
      "主进程: 3\n",
      "后台进程：2020-11-05 20:49:45   4\n",
      "主进程: 4\n",
      "后台进程：2020-11-05 20:49:46   5\n",
      "Pause!!!\n",
      "主进程: 0\n",
      "主进程: 1\n",
      "主进程: 2\n",
      "主进程: 3\n",
      "主进程: 4\n",
      "Play !!!\n",
      "后台进程：2020-11-05 20:49:52   1\n",
      "后台进程：2020-11-05 20:49:53   2\n",
      "后台进程：2020-11-05 20:49:54   3\n",
      "主进程结束，后台进程仍会继续运行！\n",
      "后台进程：2020-11-05 20:49:55   4\n",
      "后台进程：2020-11-05 20:49:56   5\n",
      "后台进程：2020-11-05 20:49:57   6\n",
      "后台进程：2020-11-05 20:49:58   7\n"
     ]
    }
   ],
   "source": [
    "#  初始化后台进程\n",
    "bt = BackstageThread()\n",
    "\n",
    "# 开始后台进程\n",
    "bt.start()\n",
    "\n",
    "# 主进程处理同时，后台进程一直运行中\n",
    "for i in range(5):\n",
    "    print('主进程: {}'.format(i))\n",
    "    time.sleep(1)\n",
    "\n",
    "# 主进程 传送指令暂停后台进程\n",
    "bt.pause()\n",
    "\n",
    "for i in range(5):\n",
    "    print('主进程: {}'.format(i))\n",
    "    time.sleep(1)\n",
    "\n",
    "# 主进程 传送指令继续后台进程\n",
    "bt.play()\n",
    "\n",
    "# 主进程 修改后台进程参数【风险点： 数据同步问题】\n",
    "bt.num = 1\n",
    "\n",
    "time.sleep(3)\n",
    "print('主进程结束，后台进程仍会继续运行！')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 定时器\n",
    "from threading import Timer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2020-11-05 20:52:07 1\n",
      "2020-11-05 20:52:08 2\n",
      "2020-11-05 20:52:09 3\n",
      "2020-11-05 20:52:10 4\n",
      "2020-11-05 20:52:11 5\n"
     ]
    }
   ],
   "source": [
    "from datetime import datetime\n",
    "from threading import Timer\n",
    "\n",
    "# 定时任务\n",
    "class Crontab(object):\n",
    "    def __init__(self):\n",
    "        self.num = 1\n",
    "\n",
    "    # 循环体主程序\n",
    "    def task_main(self):\n",
    "        print(datetime.now().strftime(\"%Y-%m-%d %H:%M:%S\"), self.num)\n",
    "        self.num += 1\n",
    "\n",
    "    # 轮询代码\n",
    "    def _polling(self, polling_time):\n",
    "        \"\"\"\n",
    "        :param polling_time:  轮询时间间隔  second\n",
    "        :return:\n",
    "        \"\"\"\n",
    "\n",
    "        # ################## 循环体主程序 ###########################\n",
    "        self.task_main()\n",
    "        # ###########################################################\n",
    "\n",
    "        # 达到指定条件 停止定时任务\n",
    "        if self.num > 5:\n",
    "            return\n",
    "        # ###########################################################\n",
    "\n",
    "        t = Timer(polling_time, self._polling, (polling_time,))\n",
    "        t.start()\n",
    "\n",
    "    def run(self):\n",
    "        # 开启定时任务， 间隔为 1 Second\n",
    "        self._polling(1)\n",
    "\n",
    "# 开始运行定时任务\n",
    "Crontab().run()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## Enum\n",
    "枚举"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "True\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "# 导入枚举类\n",
    "from enum import Enum\n",
    " \n",
    "# 继承枚举类\n",
    "class color(Enum):\n",
    "    YELLOW  = 1\n",
    "    BEOWN   = 1  # 注意BROWN的值和YELLOW的值相同，这是允许的，此时的BROWN相当于YELLOW的别名\n",
    "    RED     = 2\n",
    "    GREEN   = 3\n",
    "    PINK    = 4\n",
    "    \n",
    "print(color.YELLOW.value)\n",
    "print(color.YELLOW.value == 1)\n",
    "print(color.YELLOW.value is 1)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## namedtuple\n",
    "构造一个带字段名的元组  \n",
    "collections.namedtuple(typename, field_names, verbose=False, rename=False) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "('rank', 'suit')\n",
      "[Card(rank='1', suit='herats'), Card(rank='2', suit='diamonds')]\n",
      "[Card(rank='3', suit='herats'), Card(rank='2', suit='diamonds')]\n",
      "索引读取： 3\n",
      "名称读取： 3\n",
      "OrderedDict([('rank', '3'), ('suit', 'herats')])\n",
      "Card(rank=['1', '2'], suit=['diamonds', 'herats'])\n"
     ]
    }
   ],
   "source": [
    "from collections import namedtuple\n",
    "Card = namedtuple('Card', ['rank', 'suit'])\n",
    "# 获取所有字段名\n",
    "print(Card._fields )\n",
    "\n",
    "a = [Card('1', 'herats'), Card('2', 'diamonds')]\n",
    "print(a)\n",
    "a[0] = a[0]._replace(rank='3') # 不能直接重新赋值 a[0][0] = '3' \n",
    "print(a)\n",
    "\n",
    "print('索引读取：', a[0][0])\n",
    "print('名称读取：', a[0].rank)\n",
    "\n",
    "# 将User对象转换成字典，注意要使用\"_asdict\"\n",
    "print(a[0]._asdict())\n",
    "\n",
    "# 也可以通过一个list来创建一个User对象，这里注意需要使用\"_make\"方法\n",
    "b = Card._make([['1', '2'], ['diamonds', 'herats']])\n",
    "print(b)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## Counter"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Result :  Counter({'a': 5, 'b': 4, 'c': 3, 'd': 2, 'e': 1})\n",
      "Top 3  :  [('a', 5), ('b', 4), ('c', 3)]\n",
      "Result :  Counter({'c': 9, 'a': 5, 'b': 4, 'd': 2, 'e': 1})\n",
      "Keys   :  dict_keys(['a', 'b', 'c', 'd', 'e'])\n",
      "Values :  dict_values([5, 4, 9, 2, 1])\n"
     ]
    }
   ],
   "source": [
    "from collections import Counter\n",
    "c = Counter('abcdeabcdabcaba')\n",
    "print('Result : ', c)\n",
    "print('Top 3  : ', c.most_common(3))\n",
    "\n",
    "c.update(Counter('cccccc')) \n",
    "print('Result : ', c)\n",
    "print('Keys   : ', c.keys())\n",
    "print('Values : ', c.values())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## defaultdict"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "dict_items([('key1', 'abc')])\n",
      "dict_items([('key1', 'abc'), ('key2', 'DefaultVale')])\n"
     ]
    }
   ],
   "source": [
    "from collections import defaultdict\n",
    "\n",
    "dd = defaultdict(lambda: 'DefaultVale')\n",
    "dd['key1'] = 'abc'\n",
    "print(dd.items())\n",
    "dd['key2'] # key2不存在，返回默认值\n",
    "print(dd.items())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 扑克牌"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [],
   "source": [
    "from collections import namedtuple\n",
    "import random\n",
    "\n",
    "# 可视化 牌\n",
    "def display(cards):\n",
    "    return ' '.join([\"{1}{0}\".format(*card_i) for card_i in cards])\n",
    "\n",
    "# 创建纸牌类函数\n",
    "class FrenchDeck(object):\n",
    "    # 具名元组\n",
    "    Card = namedtuple('Card', ['rank', 'suit', 'value'])\n",
    "\n",
    "    ranks = [str(n) for n in range(3, 11)] + list('JQKA2')\n",
    "    suits = ['♢', '♣', '♡', '♠']   # ['diamonds', 'clubs', 'hearts', 'spades']  \n",
    "\n",
    "    def __init__(self, shuffle_flag=False):\n",
    "        self._cards = [self.Card(rank, suit, rank_i*4+suit_i+1) for suit_i, suit in enumerate(self.suits)\n",
    "                       for rank_i, rank in enumerate(self.ranks)]\n",
    "        # 随机洗牌\n",
    "        if shuffle_flag:\n",
    "            self.shuffle()\n",
    "            \n",
    "    def __len__(self):\n",
    "        return len(self._cards)\n",
    "\n",
    "    def __getitem__(self, position):\n",
    "        return self._cards[position]\n",
    "    \n",
    "    def __setitem__(self, position, value):\n",
    "        self._cards[position] = value \n",
    "    \n",
    "    def __delitem__(self, position): \n",
    "        del self._cards[position] \n",
    "    \n",
    "    # 返回当前牌号\n",
    "    def __str__(self): \n",
    "        return 'CardsNum:{:2d}  \\n{}'.format(len(self._cards),' '.join([\"{1}{0}\".format(*card_i) for card_i in self._cards]))\n",
    "        \n",
    "    def insert(self, position, value): \n",
    "        self._cards.insert(position, value)\n",
    "    \n",
    "    # 洗牌\n",
    "    def shuffle(self, seed=None):\n",
    "        random.seed(seed)\n",
    "        random.shuffle(self._cards)   \n",
    "\n",
    "    # 抽牌, 剩下牌数量减少\n",
    "    def sample(self, num=1):\n",
    "        return [self._cards.pop() for i in range(num) if len(self._cards) > 0]\n",
    "        "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 抽牌比大小"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " A      B \n",
      "♠A  >  ♣J \n",
      "♠8  <  ♡Q \n",
      "♢4  <  ♢2 \n",
      "♣A  <  ♡A \n",
      "♢5  <  ♣8 \n",
      "♠5  <  ♢7 \n",
      "♢10 <  ♡10\n",
      "♠Q  >  ♢Q \n",
      "♣7  <  ♠10\n",
      "♠6  <  ♠7 \n",
      "♡4  <  ♡2 \n",
      "♠4  <  ♣10\n",
      "♡6  <  ♠K \n",
      "♣5  <  ♡7 \n",
      "♣3  <  ♢K \n",
      "♢3  <  ♣2 \n",
      "♢8  <  ♢J \n",
      "♣4  <  ♣9 \n",
      "♢9  >  ♡8 \n",
      "♡K  >  ♠9 \n",
      "♢A  >  ♡J \n",
      "♡9  >  ♣6 \n",
      "♣K  <  ♠2 \n",
      "♡5  >  ♡3 \n",
      "♠3  <  ♣Q \n",
      "♠J  >  ♢6 \n",
      "\n",
      "A win: 8 \n",
      "B win: 18\n"
     ]
    }
   ],
   "source": [
    "# 初始化一副牌、随机洗牌\n",
    "deck = FrenchDeck(True) \n",
    "# print(deck)  # 显示剩下牌\n",
    "\n",
    "# # 洗牌    \n",
    "# deck.shuffle()    \n",
    "\n",
    "a_win = 0\n",
    "b_win = 0\n",
    "\n",
    "# 抽牌比大小\n",
    "print('{:^3s} {:2s} {:^3s}'.format('A','','B'))\n",
    "    \n",
    "while True:\n",
    "    # 抽牌\n",
    "    a = deck.sample(1)[0]\n",
    "    b = deck.sample(1)[0]\n",
    "    \n",
    "    if a.value>b.value:\n",
    "        a_win += 1\n",
    "    else:\n",
    "        b_win += 1\n",
    "    \n",
    "    print('{:3s} {:2s} {:3s}'.format(display([a]), '>' if a.value>b.value else '<', display([b])))\n",
    "    \n",
    "    if len(deck) < 2:\n",
    "        break\n",
    "\n",
    "print('\\nA win: {} \\nB win: {}'.format(a_win, b_win))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 21点"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "     A               B      \n",
      " ♡J ♡5 ♣10   B    ♠3 ♢4 ♣7  \n",
      " ♢2 ♠10 ♠J   B    ♠4 ♡9 ♢6  \n",
      "  ♣3 ♣4 ♣Q   A    ♡8 ♠2 ♣5  \n",
      "  ♢8 ♣J ♢9   B    ♢7 ♡3 ♣8  \n",
      " ♠A ♢10 ♡K   A    ♣6 ♠8 ♢A  \n",
      "  ♢Q ♢3 ♣A   A    ♢K ♢J ♠7  \n",
      "  ♠9 ♣9 ♠Q   B    ♡4 ♡A ♡Q  \n",
      "  ♠6 ♡7 ♢5   A   ♡10 ♠5 ♣K  \n",
      "\n",
      "A win: 4 \n",
      "B win: 4\n"
     ]
    }
   ],
   "source": [
    "# 各牌对应点数\n",
    "value_dict = {'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8,'9':9,'10':10,'J':10,'Q':10,'K':10,'A':1}\n",
    "\n",
    "# 初始化一副牌、随机洗牌\n",
    "deck = FrenchDeck(True)\n",
    "\n",
    "a_win = 0\n",
    "b_win = 0\n",
    "\n",
    "# 抽牌比大小\n",
    "print('{:^12s} {:2s} {:^12s}'.format('A','','B'))\n",
    "    \n",
    "while True:\n",
    "    # 抽牌\n",
    "    a = deck.sample(3)\n",
    "    b = deck.sample(3)\n",
    "    \n",
    "    a_point = sum([value_dict[card_i.rank] for card_i in a])\n",
    "    b_point = sum([value_dict[card_i.rank] for card_i in b])\n",
    "    \n",
    "    if 21>=a_point and (a_point>b_point or b_point>21):\n",
    "        a_win += 1\n",
    "        flag = 'A'\n",
    "        \n",
    "    elif 21>=b_point and (b_point>a_point or a_point>21):        \n",
    "        b_win += 1\n",
    "        flag = 'B'\n",
    "    \n",
    "    else:\n",
    "        flag = ' '\n",
    "    \n",
    "    print('{:^12s} {:2s} {:^12s}'.format(display(a), flag, display(b)))\n",
    "    \n",
    "    if len(deck) < 6:\n",
    "        break\n",
    "\n",
    "print('\\nA win: {} \\nB win: {}'.format(a_win, b_win))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "### 网格化参数 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [],
   "source": [
    "import copy\n",
    "##### 网格化参数，输出所有可能的参数组合【{参数字典 1}，{参数字典 2}】\n",
    "def Params_gridmesh(Params_dict):\n",
    "    '''\n",
    "    Params_dict  : 模型参数字典  {'max_depth':[5,10],'n_estimations':[10,50]}\n",
    "    '''\n",
    "    params_grid=list()\n",
    "\n",
    "    for key,params_range in Params_dict.items():\n",
    "        if len(params_grid)==0:\n",
    "            for p_value in params_range:\n",
    "                params_grid.append({key:p_value})\n",
    "               \n",
    "        else:\n",
    "            params_grid_new=list()\n",
    "            for p_value in params_range:\n",
    "                for grid in params_grid:\n",
    "                    grid_new=copy.deepcopy(grid)\n",
    "                    grid_new[key]=p_value\n",
    "                    params_grid_new.append(grid_new)\n",
    "            params_grid=params_grid_new\n",
    "            \n",
    "    return params_grid"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{'max_depth': 5, 'n_estimations': 10, 'a': 1},\n",
       " {'max_depth': 10, 'n_estimations': 10, 'a': 1},\n",
       " {'max_depth': 5, 'n_estimations': 50, 'a': 1},\n",
       " {'max_depth': 10, 'n_estimations': 50, 'a': 1},\n",
       " {'max_depth': 5, 'n_estimations': 10, 'a': 2},\n",
       " {'max_depth': 10, 'n_estimations': 10, 'a': 2},\n",
       " {'max_depth': 5, 'n_estimations': 50, 'a': 2},\n",
       " {'max_depth': 10, 'n_estimations': 50, 'a': 2}]"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Params_gridmesh({'max_depth':[5,10],'n_estimations':[10,50], 'a':[1,2]})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "### 进程监控 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['▁', '▂', '▃', '▄', '▅', '▆', '▇', '█']\n",
      "机器总内存：11.7 GB\n",
      "cpu个数：4\n",
      "psutil.Process(pid=19576, name='python.exe', started='22:40:28')\n",
      "创建用户：DESKTOP-8I3FSDO\\stuvi\n",
      "进程命令：C:\\ProgramData\\Anaconda3\\python.exe C:\\ProgramData\\Anaconda3\\Scripts\\jupyter-lab-script.py --notebook-dir=D:\\\n",
      "内存使用：41.1 MB\n"
     ]
    }
   ],
   "source": [
    "# ################################################ 进程监控\n",
    "level_char = [chr(9601 + i) for i in range(8)]\n",
    "print(level_char)\n",
    "\n",
    "import psutil  # pip install psutil\n",
    "\n",
    "print('机器总内存：{:.1f} GB'.format(psutil.virtual_memory().total / 1024 / 1024 / 1024))\n",
    "print('cpu个数：{}'.format(psutil.cpu_count()))\n",
    "# print('所有进程ID：{}'.format(list(psutil.process_iter())))\n",
    "\n",
    "pid = 19576  # 进程号码\n",
    "print(psutil.Process(pid))  # 查看对应pid的进程信息\n",
    "print('创建用户：{}'.format(psutil.Process(pid).username()))  # 查看是哪个用户创建的该进程\n",
    "print('进程命令：{}'.format(' '.join(psutil.Process(pid).cmdline())))  # 查看进程所在的路径\n",
    "print('内存使用：{:.1f} MB'.format(psutil.Process(pid).memory_info().rss / 1024 / 1024))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "### tqdm \n",
    "进度条"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|████████████████████████████████████████████████████████████████████████████████| 100/100 [00:01<00:00, 96.81it/s]\n",
      "100%|████████████████████████████████████████████████████████████████████████████████████| 4/4 [00:00<00:00,  9.86it/s]\n",
      "UserInformation Processing d: 100%|██████████████████████████████████████████████████████| 4/4 [00:00<00:00,  9.76it/s]\n"
     ]
    }
   ],
   "source": [
    "from tqdm import tqdm\n",
    "import time \n",
    "\n",
    "# 用法 一\n",
    "for i in tqdm(range(100)):  \n",
    "     #do something\n",
    "    time.sleep(0.01)\n",
    "\n",
    "# 用法 二\n",
    "for char in tqdm([\"a\", \"b\", \"c\", \"d\"]):\n",
    "    #do something\n",
    "    time.sleep(0.1)\n",
    "    \n",
    "# 用法 三\n",
    "bar = tqdm([\"a\", \"b\", \"c\", \"d\"])\n",
    "for char in bar:\n",
    "    bar.set_description(\"UserInformation Processing %s\" % char)\n",
    "    time.sleep(0.1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "PY36-tf12",
   "language": "python",
   "name": "py36_b"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
